diff --git a/DSView/pv/dialogs/waitingdialog.cpp b/DSView/pv/dialogs/waitingdialog.cpp
index b4bcdb264cb81759002c904ff21855232ad914e6..f4144ec50a24f3dcd50cf7973dffc448a32e7e74 100755
--- a/DSView/pv/dialogs/waitingdialog.cpp
+++ b/DSView/pv/dialogs/waitingdialog.cpp
@@ -170,8 +170,34 @@ void WaitingDialog::changeText()
     {
         tips->setText(tr("Waiting"));
         index = 0;
+        GVariant* gvar;
+        bool comb_comp_en = false;
+        bool zero_fgain = false;
 
-        GVariant* gvar = _dev_inst->get_config(NULL, NULL, _key);
+        gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_PROBE_COMB_COMP_EN);
+        if (gvar != NULL) {
+            comb_comp_en = g_variant_get_boolean(gvar);
+            g_variant_unref(gvar);
+            if (comb_comp_en) {
+                gvar = _dev_inst->get_config(NULL, NULL, SR_CONF_ZERO_COMB_FGAIN);
+                if (gvar != NULL) {
+                    zero_fgain = g_variant_get_boolean(gvar);
+                    g_variant_unref(gvar);
+                    if (zero_fgain) {
+                        boost::shared_ptr<view::DsoSignal> dsoSig;
+                        BOOST_FOREACH(const boost::shared_ptr<view::Signal> s, _session.get_signals())
+                        {
+                            if ((dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)))
+                                dsoSig->set_enable(dsoSig->get_index() == 0);
+                        }
+                        boost::this_thread::sleep(boost::posix_time::millisec(100));
+                        _dev_inst->set_config(NULL, NULL, SR_CONF_ZERO_COMB, g_variant_new_boolean(true));
+                    }
+                }
+            }
+        }
+
+        gvar = _dev_inst->get_config(NULL, NULL, _key);
         if (gvar != NULL) {
             bool zero = g_variant_get_boolean(gvar);
             g_variant_unref(gvar);
diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp
index dc28e0055c2375834d98db234033125e75b5750d..3debb650a1ee199eeb2ee17b191f9344f98a7fb3 100755
--- a/DSView/pv/sigsession.cpp
+++ b/DSView/pv/sigsession.cpp
@@ -505,7 +505,7 @@ bool SigSession::get_capture_status(bool &triggered, int &progress)
 {
     uint64_t sample_limits = cur_samplelimits();
     sr_status status;
-    if (sr_status_get(_dev_inst->dev_inst(), &status, true, SR_STATUS_TRIG_BEGIN, SR_STATUS_TRIG_END) == SR_OK){
+    if (sr_status_get(_dev_inst->dev_inst(), &status, true) == SR_OK){
         triggered = status.trig_hit & 0x01;
         uint64_t captured_cnt = status.trig_hit >> 2;
         captured_cnt = ((uint64_t)status.captured_cnt0 +
diff --git a/DSView/pv/storesession.cpp b/DSView/pv/storesession.cpp
index 377dfef2a268bd37776c60308988ae7760ecc649..40958fdc2a998d0f48531bb099869cd910573783 100755
--- a/DSView/pv/storesession.cpp
+++ b/DSView/pv/storesession.cpp
@@ -460,7 +460,7 @@ QString StoreSession::meta_gen(boost::shared_ptr<data::Snapshot> snapshot)
                 fprintf(meta, " vFactor%d = %" PRIu64 "\n", probecnt, probe->vfactor);
                 fprintf(meta, " vOffset%d = %d\n", probecnt, probe->hw_offset);
                 fprintf(meta, " vTrig%d = %d\n", probecnt, probe->trig_value);
-                if (sr_status_get(sdi, &status, false, 0, 0) == SR_OK) {
+                if (sr_status_get(sdi, &status, false) == SR_OK) {
                     if (probe->index == 0) {
                         fprintf(meta, " period%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_tlen);
                         fprintf(meta, " pcnt%d = %" PRIu32 "\n", probecnt, status.ch0_cyc_cnt);
diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp
index 908464c578e71cccccdb6794a4dddfb3c5067427..bf60dbf7ab056f110a10c826e1333a473eb9bcc8 100755
--- a/DSView/pv/toolbars/samplingbar.cpp
+++ b/DSView/pv/toolbars/samplingbar.cpp
@@ -804,7 +804,7 @@ void SamplingBar::commit_settings()
                                      g_variant_new_uint64(sample_rate));
             if (dev_inst->dev_inst()->mode != DSO) {
                 const uint64_t sample_count = ((uint64_t)ceil(sample_duration / SR_SEC(1) *
-                                                    sample_rate) + 1023ULL) & ~1023ULL;
+                                                    sample_rate) + SAMPLES_ALIGN) & ~SAMPLES_ALIGN;
                 if (sample_count != dev_inst->get_sample_limit())
                     dev_inst->set_config(NULL, NULL,
                                          SR_CONF_LIMIT_SAMPLES,
diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp
index 801c370b1305e45ed2e60e3c05f0832de6465df1..7999855bffd216ed5c864004a75823bbd026c7c7 100755
--- a/DSView/pv/view/dsosignal.cpp
+++ b/DSView/pv/view/dsosignal.cpp
@@ -892,7 +892,7 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right, QColor fore, QColor
         }
 
         sr_status status;
-        if (sr_status_get(_dev_inst->dev_inst(), &status, false, 0, 0) == SR_OK) {
+        if (sr_status_get(_dev_inst->dev_inst(), &status, false) == SR_OK) {
             _mValid = true;
             if (status.measure_valid) {
                 _min = (index == 0) ? status.ch0_min : status.ch1_min;
diff --git a/DSView/res/DSCopeU2B100.bin b/DSView/res/DSCopeU2B100.bin
new file mode 100644
index 0000000000000000000000000000000000000000..25c3df7f80a415e3d0541741dc99eb03e87ed136
Binary files /dev/null and b/DSView/res/DSCopeU2B100.bin differ
diff --git a/DSView/res/DSCopeU3P100.bin b/DSView/res/DSCopeU3P100.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b24ab5c9403ac0c300b91c2f9c857400d3aea906
Binary files /dev/null and b/DSView/res/DSCopeU3P100.bin differ
diff --git a/DSView/res/DSLogic33.bin b/DSView/res/DSLogic33.bin
index ea7b87a3067b5be2b3db4cf2985794accae23695..84d6a76ec36d5a6d62f11b431f7e47b2f38d8e19 100755
Binary files a/DSView/res/DSLogic33.bin and b/DSView/res/DSLogic33.bin differ
diff --git a/DSView/res/DSLogic50.bin b/DSView/res/DSLogic50.bin
index b4d8cf723117a3b6e548a0046dfb2c131b73b387..c1a80894c66e60f8b71d0941f7f8d4e7ebd87a57 100755
Binary files a/DSView/res/DSLogic50.bin and b/DSView/res/DSLogic50.bin differ
diff --git a/DSView/res/DSLogicBasic.bin b/DSView/res/DSLogicBasic.bin
index d232d1402de1b17b57c1493d35baa86f95309a2e..b52cb5889788b25f3eedc33bb86a1c9349631fe2 100755
Binary files a/DSView/res/DSLogicBasic.bin and b/DSView/res/DSLogicBasic.bin differ
diff --git a/DSView/res/DSLogicPlus.bin b/DSView/res/DSLogicPlus.bin
index 0c420e70a22688f381bab119f7b3dfa4a671697b..1235ed369aa7b604d3adb75178e190082854d35e 100755
Binary files a/DSView/res/DSLogicPlus.bin and b/DSView/res/DSLogicPlus.bin differ
diff --git a/DSView/res/DSLogicPro.bin b/DSView/res/DSLogicPro.bin
index 7b2a18d18edaef68456e25806fbfc30cf63c9b3a..ac1336a7c263e6e02fd21f929c8ba2391838ffe6 100755
Binary files a/DSView/res/DSLogicPro.bin and b/DSView/res/DSLogicPro.bin differ
diff --git a/DSView/res/DSLogicU2Basic.bin b/DSView/res/DSLogicU2Basic.bin
index b04ed19d89c171a72707ba23c8e4ce3ea05f973d..4f412821fdcfaae842d364d1046ea45b06806b56 100755
Binary files a/DSView/res/DSLogicU2Basic.bin and b/DSView/res/DSLogicU2Basic.bin differ
diff --git a/DSView/res/DSLogicU3Pro16.bin b/DSView/res/DSLogicU3Pro16.bin
new file mode 100644
index 0000000000000000000000000000000000000000..ef5fbbe6d57300bb70407948fc1e157f5b67775d
Binary files /dev/null and b/DSView/res/DSLogicU3Pro16.bin differ
diff --git a/DSView/res/DSLogicU3Pro32.bin b/DSView/res/DSLogicU3Pro32.bin
new file mode 100644
index 0000000000000000000000000000000000000000..5cfb432cfd0aa4f982bb2bf4d72816ef1c880c3a
Binary files /dev/null and b/DSView/res/DSLogicU3Pro32.bin differ
diff --git a/libsigrok4DSL/hardware/DSL/command.h b/libsigrok4DSL/hardware/DSL/command.h
index bebad27c913c17755ba3f42e168f992afe804459..bc3205316989aa610f6fc65936ac029731cf4a01 100755
--- a/libsigrok4DSL/hardware/DSL/command.h
+++ b/libsigrok4DSL/hardware/DSL/command.h
@@ -137,6 +137,14 @@ struct cmd_zero_info {
     uint8_t trans0;
     uint8_t trans1;
     uint8_t comb_comp;
+    uint8_t fgain0_code;
+    uint8_t fgain1_code;
+    uint8_t fgain2_code;
+    uint8_t fgain3_code;
+    uint8_t comb_fgain0_code;
+    uint8_t comb_fgain1_code;
+    uint8_t comb_fgain2_code;
+    uint8_t comb_fgain3_code;
 };
 
 struct cmd_vga_info {
diff --git a/libsigrok4DSL/hardware/DSL/dscope.c b/libsigrok4DSL/hardware/DSL/dscope.c
index 868808edd8ded028f23afbda46340af9d53e2f6b..81174156867d4063c84e42d9aa98c77a13c4a1bd 100755
--- a/libsigrok4DSL/hardware/DSL/dscope.c
+++ b/libsigrok4DSL/hardware/DSL/dscope.c
@@ -159,6 +159,9 @@ static struct DSL_context *DSCope_dev_new(const struct DSL_profile *prof)
     devc->trigger_hpos = 0x0;
     devc->trigger_hrate = 0;
     devc->zero = FALSE;
+    devc->zero_branch = FALSE;
+    devc->zero_comb_fgain = FALSE;
+    devc->zero_comb = FALSE;
     devc->tune = FALSE;
     devc->data_lock = FALSE;
     devc->cali = FALSE;
@@ -195,6 +198,7 @@ static GSList *scan(GSList *options)
 	libusb_device **devlist;
     int devcnt, ret, i, j;
 	const char *conn;
+    enum libusb_speed usb_speed;
 
 	drvc = di->priv;
 
@@ -236,10 +240,16 @@ static GSList *scan(GSList *options)
 			continue;
 		}
 
+        usb_speed = libusb_get_device_speed( devlist[i]);
+        if ((usb_speed != LIBUSB_SPEED_HIGH) &&
+            (usb_speed != LIBUSB_SPEED_SUPER))
+            continue;
+
 		prof = NULL;
         for (j = 0; supported_DSCope[j].vid; j++) {
             if (des.idVendor == supported_DSCope[j].vid &&
-                des.idProduct == supported_DSCope[j].pid) {
+                des.idProduct == supported_DSCope[j].pid &&
+                usb_speed == supported_DSCope[j].usb_speed) {
                 prof = &supported_DSCope[j];
 			}
 		}
@@ -343,8 +353,9 @@ static uint64_t dso_offset(const struct sr_dev_inst *sdi, const struct sr_channe
     struct DSL_context *devc = sdi->priv;
     const double offset_mid = (1 << (ch->bits - 1));
     const double offset_max = ((1 << ch->bits) - 1.0);
-    const uint64_t offset = devc->zero ? ch->zero_offset : ch->hw_offset;
-    double comb_off = 2.0 / (pow(10, 24.0*ch->comb_comp/20/4096) - 1);
+    const uint64_t offset = devc->zero ? ch->zero_offset : ch->offset;
+    double comb_off = (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) ? 0.57 / (pow(10, 24.0*ch->comb_comp/20/4096) - 1) :
+                                                                                        2.0 / (pow(10, 24.0*ch->comb_comp/20/4096) - 1);
 //    const double comb_compensate = ((devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) &&
 //                                    (dsl_en_ch_num(sdi) == 1))? (offset - offset_mid) / comb_off : 0;
     const double comb_compensate = ((ch->comb_comp != 0) && (dsl_en_ch_num(sdi) == 1)) ? (offset - offset_mid) / comb_off : 0;
@@ -385,9 +396,8 @@ static uint64_t dso_cmd_gen(const struct sr_dev_inst *sdi, struct sr_channel* ch
     switch (id) {
     case SR_CONF_PROBE_EN:
     case SR_CONF_PROBE_COUPLING:
-        if (devc->zero || sdi->mode == ANALOG || dsl_en_ch_num(sdi) == 2) {
+        if (sdi->mode == ANALOG || dsl_en_ch_num(sdi) == 2) {
             cmd += 0x0E00;
-            //cmd += 0x000;
         } else if (dsl_en_ch_num(sdi) == 1) {
             if (((ch->index == 0) && ch->enabled) || ((ch->index == 1) && !ch->enabled))
                 cmd += 0x1600;
@@ -418,7 +428,6 @@ static uint64_t dso_cmd_gen(const struct sr_dev_inst *sdi, struct sr_channel* ch
     case SR_CONF_PROBE_OFFSET:
         cmd += 0x10;
         cmd += ch->index << ch_bit;
-        ch->hw_offset = ch->offset;
         offset = dso_offset(sdi, ch);
         cmd += (offset << 8);
         break;
@@ -429,7 +438,7 @@ static uint64_t dso_cmd_gen(const struct sr_dev_inst *sdi, struct sr_channel* ch
         break;
     case SR_CONF_HORIZ_TRIGGERPOS:
         cmd += 0x20;
-        cmd += devc->trigger_hpos << 8;
+        cmd += ((uint64_t)devc->trigger_hpos << 8);
         break;
     case SR_CONF_TRIGGER_SLOPE:
         cmd += 0x28;
@@ -539,6 +548,8 @@ static gboolean dso_load_eep(struct sr_dev_inst *sdi, struct sr_channel *probe,
     zero_info.zero_addr = dst_addr;
     if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_SEEP)
         real_zero_addr = zero_info.zero_addr;
+    else if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_FLASH)
+        real_zero_addr = probe->index * DSO_ZERO_PAGE;
     else
         real_zero_addr = (zero_big_addr << 8) + zero_info.zero_addr;
     if ((ret = dsl_rd_nvm(sdi, (unsigned char *)&zero_info, real_zero_addr, sizeof(struct cmd_zero_info))) != SR_OK) {
@@ -555,6 +566,16 @@ static gboolean dso_load_eep(struct sr_dev_inst *sdi, struct sr_channel *probe,
                  probe->comb_diff_bom = *(preoff_ptr + 2*i + 1);
                  probe->vpos_trans = *(preoff_ptr + 2*i + 2) + (*(preoff_ptr + 2*i + 3) << 8);
                  probe->comb_comp = *(preoff_ptr + 2*i + 4);
+                 probe->digi_fgain = *(preoff_ptr + 2*i + 5) + (*(preoff_ptr + 2*i + 6) << 8);
+                 probe->cali_fgain0 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 7));
+                 probe->cali_fgain1 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 8));
+                 probe->cali_fgain2 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 9));
+                 probe->cali_fgain3 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 10));
+                 probe->cali_comb_fgain0 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 11));
+                 probe->cali_comb_fgain1 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 12));
+                 probe->cali_comb_fgain2 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 13));
+                 probe->cali_comb_fgain3 = dsl_adc_code2fgain(*(preoff_ptr + 2*i + 14));
+
                  if (!fpga_done) {
                      const double slope = (probe->comb_diff_bom - probe->comb_diff_top)/(2.0*255.0);
                      for (i = 0; i < 256; i++) {
@@ -575,6 +596,8 @@ static gboolean dso_load_eep(struct sr_dev_inst *sdi, struct sr_channel *probe,
     vga_info.vga_addr = dst_addr + sizeof(struct cmd_zero_info);
     if (devc ->profile->dev_caps.feature_caps & CAPS_FEATURE_SEEP)
         real_zero_addr = vga_info.vga_addr;
+    else if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_FLASH)
+        real_zero_addr = probe->index * DSO_ZERO_PAGE + 1;
     else
         real_zero_addr = (zero_big_addr << 8) + vga_info.vga_addr;
     if ((ret = dsl_rd_nvm(sdi, (unsigned char *)&vga_info, real_zero_addr, sizeof(struct cmd_vga_info))) != SR_OK) {
@@ -594,6 +617,396 @@ static gboolean dso_load_eep(struct sr_dev_inst *sdi, struct sr_channel *probe,
     return TRUE;
 }
 
+static int dso_zero(const struct sr_dev_inst *sdi, gboolean reset)
+{
+    struct DSL_context *devc = sdi->priv;
+    GSList *l;
+    int ret = SR_OK;
+    struct sr_usb_dev_inst *usb;
+    struct libusb_device_handle *hdl;
+    struct ctl_wr_cmd wr_cmd;
+
+    static uint64_t vdiv_back[2] = {0, 0};
+    struct sr_channel *probe0 = NULL, *probe1 = NULL;
+    uint16_t offset_top;
+    if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511)
+        offset_top = 15;
+    else
+        offset_top = 20;
+    const uint16_t offset_bom = ((1 << channel_modes[devc->ch_mode].unit_bits) - 1) - offset_top;
+    const uint16_t offset_mid = (1 << (channel_modes[devc->ch_mode].unit_bits - 1));
+    const uint16_t max_trans = ((1 << 10) - 1);
+
+    #ifdef _WIN32
+    const int zero_interval = (devc->profile->usb_speed == LIBUSB_SPEED_SUPER) ? 10 : 4;
+    #else
+    const int zero_interval = 50;
+    #endif
+    const double margin_pass = 0.3;
+    int end_cnt = 0;
+    const int branch_done_cnt = (devc->profile->usb_speed == LIBUSB_SPEED_SUPER) ? 10 : 2;
+    static gboolean warm_done = FALSE;
+    static gboolean trans_fix_done = FALSE;
+    static gboolean mid_zero_done = FALSE;
+    static double margin[2];
+    //static double offset[2];
+    double acc_mean = 0;
+    double acc_mean0 = 0;
+    double acc_mean1 = 0;
+    double acc_skew[8];
+    double acc_max_skew;
+
+    if (reset) {
+        warm_done = FALSE;
+        trans_fix_done = FALSE;
+        mid_zero_done = FALSE;
+        vdiv_back[0] = 0;
+        vdiv_back[1] = 0;
+        return SR_OK;
+    }
+    if (!devc->mstatus_valid)
+        return SR_ERR_ARG;
+
+    usb = sdi->conn;
+    hdl = usb->devhdl;
+    for(l = sdi->channels; l; l = l->next) {
+        struct sr_channel *probe = (struct sr_channel *)l->data;
+        if (probe->index == 0)
+            probe0 = probe;
+        if (probe->index == 1)
+            probe1 = probe;
+        if (vdiv_back[probe->index] == 0)
+            vdiv_back[probe->index] = probe->vdiv;
+    }
+
+    if (!trans_fix_done && devc->zero_stage == 0) {
+        ret = SR_OK;
+        if (!warm_done) {
+            if (devc->zero_pcnt == 0*zero_interval) {
+                for(l = sdi->channels; l; l = l->next) {
+                    struct sr_channel *probe = (struct sr_channel *)l->data;
+                    for (int i = 0; (probe->vga_ptr+i)->key; i++)
+                        probe->vdiv = (probe->vga_ptr+i)->key;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_VDIV));
+                    probe->zero_offset = offset_mid;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
+                }
+            }
+            if (!(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) ||
+                (devc->zero_pcnt == 1*zero_interval)) {
+                warm_done = TRUE;
+                devc->zero_pcnt = 0*zero_interval-1;
+            }
+        } else if (!(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_PREOFF)) {
+            if (devc->zero_pcnt == 0*zero_interval) {
+                for(l = sdi->channels; l; l = l->next) {
+                    struct sr_channel *probe = (struct sr_channel *)l->data;
+                    probe->zero_offset = offset_bom;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
+                }
+            }
+            if (devc->zero_pcnt == 1*zero_interval) {
+                margin[0] = (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
+                margin[1] = (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
+//                if (margin[0] >= value_max || margin[1] >= value_max)
+//                    ret = SR_ERR;
+            }
+            if (devc->zero_pcnt == 1*zero_interval+1) {
+                for(l = sdi->channels; l; l = l->next) {
+                    struct sr_channel *probe = (struct sr_channel *)l->data;
+                    probe->zero_offset = offset_top;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
+                }
+            }
+            if (devc->zero_pcnt == 2*zero_interval) {
+                double top0 = (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
+                double top1 = (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
+//                if (top0 <= value_min || top1 <= value_min) {
+//                    ret = SR_ERR;
+                //} else {
+                    margin[0] -= top0;
+                    margin[1] -= top1;
+                    for(l = sdi->channels; l; l = l->next) {
+                        struct sr_channel *probe = (struct sr_channel *)l->data;
+                        margin[probe->index] -= (offset_bom - offset_top);
+                        if (fabs(margin[probe->index]) > margin_pass) {
+                            margin[probe->index] = margin[probe->index] > 0 ? ceil(margin[probe->index]) : floor(margin[probe->index]);
+                            probe->vpos_trans = min(probe->vpos_trans - margin[probe->index], max_trans);
+                            ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
+                        } else {
+                            margin[probe->index] = 0;
+                        }
+                    }
+                    trans_fix_done = (margin[0] == 0) && (margin[1] == 0);
+                    devc->zero_pcnt = trans_fix_done ? 0*zero_interval : 0*zero_interval-1;
+                //}
+            }
+        } else {
+            trans_fix_done = TRUE;
+        }
+
+        if (!trans_fix_done && ret == SR_OK)
+            devc->zero_pcnt++;
+    } else if (!mid_zero_done) {
+        if (devc->zero_pcnt == 0) {
+            for(l = sdi->channels; l; l = l->next) {
+                struct sr_channel *probe = (struct sr_channel *)l->data;
+                probe->vdiv = (probe->vga_ptr+devc->zero_stage)->key;
+                if (probe->vdiv == 0) {
+                    probe->vdiv = (probe->vga_ptr+devc->zero_stage-1)->key;
+                    mid_zero_done = TRUE;
+                    break;
+                }
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_VDIV));
+                probe->zero_offset = offset_mid;
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
+                // must after offset setting
+                probe->vdiv = vdiv_back[probe->index];
+            }
+        }
+
+        if (devc->zero_pcnt == zero_interval) {
+            margin[0] = offset_mid - (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
+            margin[1] = offset_mid - (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
+            if (fabs(margin[0]) < margin_pass && fabs(margin[1]) < margin_pass) {
+                devc->zero_stage++;
+            } else {
+                if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_PREOFF) {
+                    for(l = sdi->channels; l; l = l->next) {
+                        struct sr_channel *probe = (struct sr_channel *)l->data;
+                        double trans_coarse = ((probe->vga_ptr+devc->zero_stage)->key < 500) ? (probe->vpos_trans >> 8)/DSCOPE_TRANS_CMULTI : (probe->vpos_trans >> 8);
+                        double trans_fine = ((probe->vga_ptr+devc->zero_stage)->key < 500) ? (probe->vpos_trans & 0x00ff) / 1000.0 : (probe->vpos_trans & 0x00ff) / DSCOPE_TRANS_FMULTI;
+
+                        double voltage_margin = margin[probe->index] * (probe->vga_ptr+devc->zero_stage)->key * 10 / 255.0;
+                        uint16_t last_preoff = (probe->vga_ptr+devc->zero_stage)->preoff;
+                        int preoff_coarse = floor(voltage_margin / trans_coarse + 0.5);
+                        int preoff_fine = floor(-(voltage_margin - preoff_coarse*trans_coarse)/trans_fine + 0.5);
+                        preoff_coarse = (last_preoff >> 10) + preoff_coarse;
+                        preoff_fine = (last_preoff&0x03ff) + preoff_fine;
+                        (probe->vga_ptr+devc->zero_stage)->preoff = (preoff_coarse << 10) + preoff_fine;
+                    }
+                } else {
+                    for(l = sdi->channels; l; l = l->next) {
+                        struct sr_channel *probe = (struct sr_channel *)l->data;
+                        (probe->vga_ptr+devc->zero_stage)->preoff += margin[probe->index] > 0 ? ceil(margin[probe->index]) : floor(margin[probe->index]);
+                    }
+                }
+            }
+            devc->zero_pcnt = 0;
+        } else if (!mid_zero_done) {
+            devc->zero_pcnt++;
+        }
+    } else {
+        ret = SR_OK;
+        end_cnt = 0*zero_interval + 1;
+        if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) {
+            if (!devc->zero_comb_fgain) {
+                if (devc->zero_pcnt == 0*zero_interval+1) {
+                    devc->zero_branch = TRUE;
+
+                    probe0->zero_offset = offset_bom;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
+                    probe1->zero_offset = offset_bom;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
+
+                    dsl_probe_cali_fgain(devc, probe0, 1, FALSE, TRUE);
+                    dsl_probe_cali_fgain(devc, probe1, 1, FALSE, TRUE);
+                    dsl_config_adc_fgain(sdi, 0, probe0->cali_fgain0, probe0->cali_fgain1);
+                    dsl_config_adc_fgain(sdi, 1, probe0->cali_fgain2, probe0->cali_fgain3);
+                    dsl_config_adc_fgain(sdi, 2, probe1->cali_fgain0, probe1->cali_fgain1);
+                    dsl_config_adc_fgain(sdi, 3, probe1->cali_fgain2, probe1->cali_fgain3);
+                    acc_mean0 = 0;
+                    acc_mean1 = 0;
+                } else if (devc->zero_pcnt == branch_done_cnt*zero_interval) {
+                    acc_mean0 = (devc->mstatus.ch0_acc_mean + devc->mstatus.ch0_acc_mean_p1 +
+                                 devc->mstatus.ch0_acc_mean_p2 + devc->mstatus.ch0_acc_mean_p3) / 4.0;
+                    acc_mean1 = (devc->mstatus.ch1_acc_mean + devc->mstatus.ch1_acc_mean_p1 +
+                                 devc->mstatus.ch1_acc_mean_p2 + devc->mstatus.ch1_acc_mean_p3) / 4.0;
+
+                    acc_skew[0] = devc->mstatus.ch0_acc_mean / acc_mean0 - 1;
+                    acc_skew[1] = devc->mstatus.ch0_acc_mean_p1 / acc_mean0 - 1;
+                    acc_skew[2] = devc->mstatus.ch0_acc_mean_p2 / acc_mean0 - 1;
+                    acc_skew[3] = devc->mstatus.ch0_acc_mean_p3 / acc_mean0 - 1;
+                    acc_skew[4] = devc->mstatus.ch1_acc_mean / acc_mean1 - 1;
+                    acc_skew[5] = devc->mstatus.ch1_acc_mean_p1 / acc_mean1 - 1;
+                    acc_skew[6] = devc->mstatus.ch1_acc_mean_p2 / acc_mean1 - 1;
+                    acc_skew[7] = devc->mstatus.ch1_acc_mean_p3 / acc_mean1 - 1;
+                    acc_max_skew = fabs(acc_skew[0]);
+                    for (int i=1; i <8; i++)
+                        acc_max_skew = max(acc_max_skew, fabs(acc_skew[i]));
+                    if ((acc_max_skew > MAX_ACC_VARIANCE) && (dsl_probe_fgain_inrange(probe0, FALSE, acc_skew) ||
+                                                              dsl_probe_fgain_inrange(probe1, FALSE, acc_skew))) {
+                        devc->zero_pcnt = 0*zero_interval+1;
+
+                        dsl_probe_cali_fgain(devc, probe0, acc_mean0, FALSE, FALSE);
+                        dsl_probe_cali_fgain(devc, probe1, acc_mean1, FALSE, FALSE);
+
+                        dsl_config_adc_fgain(sdi, 0, probe0->cali_fgain0, probe0->cali_fgain1);
+                        dsl_config_adc_fgain(sdi, 1, probe0->cali_fgain2, probe0->cali_fgain3);
+                        dsl_config_adc_fgain(sdi, 2, probe1->cali_fgain0, probe1->cali_fgain1);
+                        dsl_config_adc_fgain(sdi, 3, probe1->cali_fgain2, probe1->cali_fgain3);
+                    } else {
+                        if (acc_max_skew <= MAX_ACC_VARIANCE) {
+                            devc->zero_comb_fgain = TRUE;
+                            devc->zero_pcnt = 0*zero_interval;
+                        } else {
+                            devc->zero_pcnt = 0*zero_interval;
+                            dsl_skew_fpga_fgain(sdi, FALSE, acc_skew);
+                        }
+                    }
+                }
+            }
+            if (devc->zero_comb_fgain) {
+                if (devc->zero_pcnt == 0*zero_interval+1) {
+                    probe0->zero_offset = offset_bom;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
+                    probe1->zero_offset = offset_bom;
+                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
+
+                    acc_mean = 0;
+                    devc->zero_comb = FALSE;
+                    dsl_probe_cali_fgain(devc, probe0, 1, TRUE, TRUE);
+                    dsl_probe_cali_fgain(devc, probe1, 1, TRUE, TRUE);
+                    dsl_config_adc_fgain(sdi, 0, probe0->cali_comb_fgain0, probe0->cali_comb_fgain1);
+                    dsl_config_adc_fgain(sdi, 1, probe0->cali_comb_fgain2, probe0->cali_comb_fgain3);
+                    dsl_config_adc_fgain(sdi, 2, probe1->cali_comb_fgain0, probe1->cali_comb_fgain1);
+                    dsl_config_adc_fgain(sdi, 3, probe1->cali_comb_fgain2, probe1->cali_comb_fgain3);
+                } else if (devc->zero_pcnt == 1*zero_interval) {
+                    if (!devc->zero_comb)
+                        devc->zero_pcnt = 0*zero_interval+1;
+                } else if (devc->zero_pcnt == branch_done_cnt*zero_interval) {
+                    acc_mean = (devc->mstatus.ch0_acc_mean + devc->mstatus.ch0_acc_mean_p1 +
+                                devc->mstatus.ch0_acc_mean_p2 + devc->mstatus.ch0_acc_mean_p3 +
+                                devc->mstatus.ch1_acc_mean + devc->mstatus.ch1_acc_mean_p1 +
+                                devc->mstatus.ch1_acc_mean_p2 + devc->mstatus.ch1_acc_mean_p3) / 8.0;
+
+                    acc_skew[0] = devc->mstatus.ch0_acc_mean / acc_mean - 1;
+                    acc_skew[1] = devc->mstatus.ch0_acc_mean_p1 / acc_mean - 1;
+                    acc_skew[2] = devc->mstatus.ch0_acc_mean_p2 / acc_mean - 1;
+                    acc_skew[3] = devc->mstatus.ch0_acc_mean_p3 / acc_mean - 1;
+                    acc_skew[4] = devc->mstatus.ch1_acc_mean / acc_mean - 1;
+                    acc_skew[5] = devc->mstatus.ch1_acc_mean_p1 / acc_mean - 1;
+                    acc_skew[6] = devc->mstatus.ch1_acc_mean_p2 / acc_mean - 1;
+                    acc_skew[7] = devc->mstatus.ch1_acc_mean_p3 / acc_mean - 1;
+                    acc_max_skew = fabs(acc_skew[0]);
+                    for (int i=1; i <8; i++)
+                        acc_max_skew = max(acc_max_skew, fabs(acc_skew[i]));
+                    if ((acc_max_skew > MAX_ACC_VARIANCE) && (dsl_probe_fgain_inrange(probe0, TRUE, acc_skew) ||
+                                                              dsl_probe_fgain_inrange(probe1, TRUE, acc_skew))) {
+                        devc->zero_pcnt = 0*zero_interval+1;
+
+                        dsl_probe_cali_fgain(devc, probe0, acc_mean, TRUE, FALSE);
+                        dsl_probe_cali_fgain(devc, probe1, acc_mean, TRUE, FALSE);
+
+                        dsl_config_adc_fgain(sdi, 0, probe0->cali_comb_fgain0, probe0->cali_comb_fgain1);
+                        dsl_config_adc_fgain(sdi, 1, probe0->cali_comb_fgain2, probe0->cali_comb_fgain3);
+                        dsl_config_adc_fgain(sdi, 2, probe1->cali_comb_fgain0, probe1->cali_comb_fgain1);
+                        dsl_config_adc_fgain(sdi, 3, probe1->cali_comb_fgain2, probe1->cali_comb_fgain3);
+                    } else {
+                        if (acc_max_skew <= MAX_ACC_VARIANCE) {
+                            devc->zero_comb_fgain = FALSE;
+                            devc->zero_branch = FALSE;
+                        } else {
+                            devc->zero_pcnt = 0*zero_interval;
+                            dsl_skew_fpga_fgain(sdi, TRUE, acc_skew);
+                        }
+                    }
+                }
+            }
+            end_cnt = branch_done_cnt*zero_interval + 1;
+        } else {
+            if (devc->zero_pcnt == 0*zero_interval+1) {
+                ret = dsl_wr_reg(sdi, COMB_ADDR+6, 0b1101);
+                wr_cmd.header.dest = DSL_CTL_DSO_EN1;
+                wr_cmd.data[0] = (uint8_t)~bmCH_CH1;
+                wr_cmd.header.size = 1;
+                ret = command_ctl_wr(hdl, wr_cmd);
+
+                probe0->zero_offset = offset_top;
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
+            } else if (devc->zero_pcnt == 1*zero_interval) {
+                probe0->comb_diff_top = ((devc->mstatus.ch0_acc_mean * 2.0 - devc->mstatus.ch1_acc_mean * 2.0) / devc->limit_samples);
+                probe0->zero_offset = offset_bom;
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
+            } else if (devc->zero_pcnt == 2*zero_interval) {
+                probe0->comb_diff_bom = ((devc->mstatus.ch0_acc_mean * 2.0 - devc->mstatus.ch1_acc_mean * 2.0) / devc->limit_samples);
+            }
+
+            if (devc->zero_pcnt == 2*zero_interval+1) {
+                ret = dsl_wr_reg(sdi, COMB_ADDR+6, 0b1110);
+                wr_cmd.header.dest = DSL_CTL_DSO_EN1;
+                wr_cmd.data[0] = bmCH_CH1;
+                wr_cmd.header.size = 1;
+                ret = command_ctl_wr(hdl, wr_cmd);
+                wr_cmd.header.dest = DSL_CTL_DSO_EN0;
+                wr_cmd.data[0] = (uint8_t)~bmCH_CH0;
+                wr_cmd.header.size = 1;
+                ret = command_ctl_wr(hdl, wr_cmd);
+
+                probe1->zero_offset = offset_top;
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
+            } else if (devc->zero_pcnt == 3*zero_interval) {
+                probe1->comb_diff_top = ((devc->mstatus.ch1_acc_mean * 2.0 - devc->mstatus.ch0_acc_mean * 2.0) / devc->limit_samples);
+                probe1->zero_offset = offset_bom;
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
+            } else if (devc->zero_pcnt == 4*zero_interval) {
+                probe1->comb_diff_bom = ((devc->mstatus.ch1_acc_mean * 2.0 - devc->mstatus.ch0_acc_mean * 2.0) / devc->limit_samples);
+            }
+
+            end_cnt = 4*zero_interval+1;
+        }
+
+        if (ret == SR_OK)
+            devc->zero_pcnt++;
+
+        if (devc->zero_pcnt == end_cnt) {
+            for(l = sdi->channels; l; l = l->next) {
+                struct sr_channel *probe = (struct sr_channel *)l->data;
+                probe->vdiv = vdiv_back[probe->index];
+                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_VDIV));
+
+                // vgain tunning
+                if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_AUTO_VGAIN) {
+                    if (probe->vga_ptr != NULL) {
+                        for (uint16_t i = 0; devc->profile->dev_caps.vdivs[i]; i++) {
+                            for (uint16_t j = 0; j < ARRAY_SIZE(vga_defaults); j++) {
+                                if (vga_defaults[j].id == devc->profile->dev_caps.vga_id &&
+                                    vga_defaults[j].key == devc->profile->dev_caps.vdivs[i]) {
+                                    const int64_t vgain_delta = probe->vpos_trans > devc->profile->dev_caps.default_pwmtrans ?
+                                                ((int64_t)(probe->vpos_trans - devc->profile->dev_caps.default_pwmtrans) << 8) :
+                                                (((int64_t)(probe->vpos_trans - devc->profile->dev_caps.default_pwmtrans) << 7) & 0xFFFFFF00);
+                                    (probe->vga_ptr+i)->vgain = vga_defaults[j].vgain + vgain_delta;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            ret = dsl_wr_reg(sdi, COMB_ADDR+6, 0b0011);
+            wr_cmd.header.dest = DSL_CTL_DSO_EN0;
+            wr_cmd.data[0] = bmCH_CH0;
+            wr_cmd.header.size = 1;
+            ret = command_ctl_wr(hdl, wr_cmd);
+            wr_cmd.header.dest = DSL_CTL_DSO_EN1;
+            wr_cmd.data[0] = bmCH_CH1;
+            wr_cmd.header.size = 1;
+            ret = command_ctl_wr(hdl, wr_cmd);
+
+            devc->zero = FALSE;
+            warm_done = FALSE;
+            trans_fix_done = FALSE;
+            mid_zero_done = FALSE;
+            vdiv_back[0] = 0;
+            vdiv_back[1] = 0;
+            dso_init(sdi);
+        }
+    }
+
+    return ret;
+}
+
 static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
                       const struct sr_channel *ch,
                       const struct sr_channel_group *cg)
@@ -651,9 +1064,9 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
             *data = g_variant_new_uint64(dso_vga(ch)>>8);
             break;
         case SR_CONF_PROBE_COMB_COMP_EN:
-            if (!sdi || !ch)
+            if (!sdi)
                 return SR_ERR;
-            *data = g_variant_new_boolean(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511);
+            *data = g_variant_new_boolean((devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) != 0);
             break;
         case SR_CONF_PROBE_COMB_COMP:
             if (!sdi || !ch)
@@ -1065,6 +1478,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
                     }
                 }
             }  
+        } else {
+            dso_zero(sdi, TRUE);
         }
     } else if (id == SR_CONF_ZERO_DEFAULT) {
         unsigned int i, j;
@@ -1072,6 +1487,15 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
             struct sr_channel *probe = (struct sr_channel *)l->data;
             probe->vpos_trans = devc->profile->dev_caps.default_pwmtrans;
             probe->comb_comp = devc->profile->dev_caps.default_comb_comp;
+            probe->digi_fgain = 0;
+            probe->cali_fgain0 = 1;
+            probe->cali_fgain1 = 1;
+            probe->cali_fgain2 = 1;
+            probe->cali_fgain3 = 1;
+            probe->cali_comb_fgain0 = 1;
+            probe->cali_comb_fgain1 = 1;
+            probe->cali_comb_fgain2 = 1;
+            probe->cali_comb_fgain3 = 1;
             if (probe->vga_ptr != NULL) {
                 for (i = 0; devc->profile->dev_caps.vdivs[i]; i++) {
                     for (j = 0; j < ARRAY_SIZE(vga_defaults); j++) {
@@ -1120,6 +1544,16 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
                 *(preoff_ptr+2*i+2) = (probe->vpos_trans&0x00FF);
                 *(preoff_ptr+2*i+3) = (probe->vpos_trans>>8);
                 *(preoff_ptr+2*i+4) = probe->comb_comp;
+                *(preoff_ptr+2*i+5) = (probe->digi_fgain&0x00FF);
+                *(preoff_ptr+2*i+6) = (probe->digi_fgain>>8);
+                *(preoff_ptr+2*i+7) = dsl_adc_fgain2code(probe->cali_fgain0);
+                *(preoff_ptr+2*i+8) = dsl_adc_fgain2code(probe->cali_fgain1);
+                *(preoff_ptr+2*i+9) = dsl_adc_fgain2code(probe->cali_fgain2);
+                *(preoff_ptr+2*i+10) = dsl_adc_fgain2code(probe->cali_fgain3);
+                *(preoff_ptr+2*i+11) = dsl_adc_fgain2code(probe->cali_comb_fgain0);
+                *(preoff_ptr+2*i+12) = dsl_adc_fgain2code(probe->cali_comb_fgain1);
+                *(preoff_ptr+2*i+13) = dsl_adc_fgain2code(probe->cali_comb_fgain2);
+                *(preoff_ptr+2*i+14) = dsl_adc_fgain2code(probe->cali_comb_fgain3);
 
                 vga_info.vga_addr = zero_info.zero_addr + sizeof(struct cmd_zero_info);
                 uint16_t *vgain_ptr = &vga_info.vga0;
@@ -1130,6 +1564,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
                 if (ret == SR_OK) {
                     if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_SEEP)
                         real_zero_addr = zero_info.zero_addr;
+                    else if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_FLASH)
+                        real_zero_addr = probe->index * DSO_ZERO_PAGE;
                     else
                         real_zero_addr = (zero_big_addr << 8) + zero_info.zero_addr;
                     ret = dsl_wr_nvm(sdi, (unsigned char *)&zero_info, real_zero_addr, sizeof(struct cmd_zero_info));
@@ -1137,6 +1573,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
                 if (ret == SR_OK) {
                     if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_SEEP)
                         real_zero_addr = vga_info.vga_addr;
+                    else if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_FLASH)
+                        real_zero_addr = probe->index * DSO_ZERO_PAGE + 1;
                     else
                         real_zero_addr = (zero_big_addr << 8) + vga_info.vga_addr;
                     ret = dsl_wr_nvm(sdi, (unsigned char *)&vga_info, real_zero_addr, sizeof(struct cmd_vga_info));
@@ -1260,269 +1698,6 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
     return SR_OK;
 }
 
-static int dso_zero(const struct sr_dev_inst *sdi)
-{
-    struct DSL_context *devc = sdi->priv;
-    GSList *l;
-    int ret;
-    struct sr_usb_dev_inst *usb;
-    struct libusb_device_handle *hdl;
-    struct ctl_wr_cmd wr_cmd;
-
-    static uint64_t vdiv_back[2];
-    struct sr_channel *probe0 = NULL, *probe1 = NULL;
-    const uint16_t offset_top = 20;
-    const uint16_t offset_bom = ((1 << channel_modes[devc->ch_mode].unit_bits) - 1) - offset_top;
-    const uint16_t offset_mid = (1 << (channel_modes[devc->ch_mode].unit_bits - 1));
-    const uint16_t max_trans = ((1 << 10) - 1);
-    const uint8_t value_min = 0;
-    const uint8_t value_max = (1 << channel_modes[devc->ch_mode].unit_bits) - 1;
-
-    const int zero_interval = 10;
-    const double margin_pass = 0.3;
-    int end_cnt = 0;
-    static gboolean trans_fix_done = FALSE;
-    static gboolean mid_zero_done = FALSE;
-    static double margin[2];
-    //static double offset[2];
-
-    usb = sdi->conn;
-    hdl = usb->devhdl;
-    for(l = sdi->channels; l; l = l->next) {
-        struct sr_channel *probe = (struct sr_channel *)l->data;
-        if (probe->index == 0)
-            probe0 = probe;
-        if (probe->index == 1)
-            probe1 = probe;
-        vdiv_back[probe->index] = probe->vdiv;
-    }
-
-    if (!trans_fix_done && devc->zero_stage == 0) {
-        ret = SR_OK;
-        if (!(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_PREOFF)) {
-            if (devc->zero_pcnt == 0*zero_interval) {
-                for(l = sdi->channels; l; l = l->next) {
-                    struct sr_channel *probe = (struct sr_channel *)l->data;
-                    probe->zero_offset = offset_bom;
-                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
-                }
-            }
-            if (devc->zero_pcnt == 1*zero_interval) {
-                margin[0] = (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
-                margin[1] = (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
-                if (margin[0] >= value_max || margin[1] >= value_max)
-                    ret = SR_ERR;
-            }
-            if (devc->zero_pcnt == 1*zero_interval+1) {
-                for(l = sdi->channels; l; l = l->next) {
-                    struct sr_channel *probe = (struct sr_channel *)l->data;
-                    probe->zero_offset = offset_top;
-                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
-                }
-            }
-            if (devc->zero_pcnt == 2*zero_interval) {
-                double top0 = (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
-                double top1 = (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
-                if (top0 <= value_min || top1 <= value_min) {
-                    ret = SR_ERR;
-                } else {
-                    margin[0] -= top0;
-                    margin[1] -= top1;
-                    for(l = sdi->channels; l; l = l->next) {
-                        struct sr_channel *probe = (struct sr_channel *)l->data;
-                        margin[probe->index] -= (offset_bom - offset_top);
-                        if (fabs(margin[probe->index]) > margin_pass) {
-                            margin[probe->index] = margin[probe->index] > 0 ? ceil(margin[probe->index]) : floor(margin[probe->index]);
-                            probe->vpos_trans = min(probe->vpos_trans - margin[probe->index], max_trans);
-                            ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
-                        } else {
-                            margin[probe->index] = 0;
-                        }
-                    }
-                    trans_fix_done = (margin[0] == 0) && (margin[1] == 0);
-                    devc->zero_pcnt = trans_fix_done ? 0*zero_interval : 0*zero_interval-1;
-                }
-            }
-        } else {
-            trans_fix_done = TRUE;
-        }
-
-        if (!trans_fix_done && ret == SR_OK)
-            devc->zero_pcnt++;
-    } else if (!mid_zero_done) {
-        if (devc->zero_pcnt == 0) {
-            for(l = sdi->channels; l; l = l->next) {
-                struct sr_channel *probe = (struct sr_channel *)l->data;
-                probe->vdiv = (probe->vga_ptr+devc->zero_stage)->key;
-                if (probe->vdiv == 0) {
-                    probe->vdiv = vdiv_back[probe->index];
-                    mid_zero_done = TRUE;
-                    break;
-                }
-                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_VDIV));
-                probe->zero_offset = offset_mid;
-                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
-                // must after offset setting
-                probe->vdiv = vdiv_back[probe->index];
-            }
-        }
-
-        if (devc->zero_pcnt == zero_interval) {
-            margin[0] = offset_mid - (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
-            margin[1] = offset_mid - (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
-            if (fabs(margin[0]) < margin_pass && fabs(margin[1]) < margin_pass) {
-                devc->zero_stage++;
-            } else {
-                if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_PREOFF) {
-                    for(l = sdi->channels; l; l = l->next) {
-                        struct sr_channel *probe = (struct sr_channel *)l->data;
-                        double trans_coarse = ((probe->vga_ptr+devc->zero_stage)->key < 500) ? (probe->vpos_trans >> 8)/DSCOPE_TRANS_CMULTI : (probe->vpos_trans >> 8);
-                        double trans_fine = ((probe->vga_ptr+devc->zero_stage)->key < 500) ? (probe->vpos_trans & 0x00ff) / 1000.0 : (probe->vpos_trans & 0x00ff) / DSCOPE_TRANS_FMULTI;
-
-                        double voltage_margin = margin[probe->index] * (probe->vga_ptr+devc->zero_stage)->key * 10 / 255.0;
-                        uint16_t last_preoff = (probe->vga_ptr+devc->zero_stage)->preoff;
-                        int preoff_coarse = floor(voltage_margin / trans_coarse + 0.5);
-                        int preoff_fine = floor(-(voltage_margin - preoff_coarse*trans_coarse)/trans_fine + 0.5);
-                        preoff_coarse = (last_preoff >> 10) + preoff_coarse;
-                        preoff_fine = (last_preoff&0x03ff) + preoff_fine;
-                        (probe->vga_ptr+devc->zero_stage)->preoff = (preoff_coarse << 10) + preoff_fine;
-                    }
-                } else {
-                    for(l = sdi->channels; l; l = l->next) {
-                        struct sr_channel *probe = (struct sr_channel *)l->data;
-                        (probe->vga_ptr+devc->zero_stage)->preoff += margin[probe->index] > 0 ? ceil(margin[probe->index]) : floor(margin[probe->index]);
-                    }
-                }
-            }
-            devc->zero_pcnt = 0;
-        } else if (!mid_zero_done) {
-            devc->zero_pcnt++;
-        }
-    } else {
-        ret = SR_OK;
-        end_cnt = 0*zero_interval + 1;
-        if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) {
-//            if (devc->zero_pcnt == 0*zero_interval+1) {
-//                for(l = sdi->channels; l; l = l->next) {
-//                    struct sr_channel *probe = (struct sr_channel *)l->data;
-//                    probe->zero_offset = offset_bom;
-//                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
-//                }
-//            }
-//            if (devc->zero_pcnt == 1*zero_interval) {
-//                offset[0] = (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
-//                offset[1] = (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
-//                if (margin[0] >= value_max || margin[1] >= value_max)
-//                    ret = SR_ERR;
-//            }
-//            if (devc->zero_pcnt == 1*zero_interval+1) {
-//                dsl_config_adc(sdi, adc_single_ch0);
-//                probe0->enabled = TRUE;
-//                probe1->enabled = FALSE;
-
-//                probe0->zero_offset = offset_bom;
-//                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
-//            }
-//            if (devc->zero_pcnt == 2*zero_interval) {
-//                margin[0] = offset[0] - (devc->mstatus.ch0_acc_mean * 1.0 / devc->limit_samples);
-//                if (fabs(margin[0]) > margin_pass) {
-//                    probe0->comb_comp -= margin[0] > 0 ? ceil(margin[0]) : floor(margin[0]);
-//                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
-//                    devc->zero_pcnt = 1*zero_interval+1;
-//                }
-//            }
-//            if (devc->zero_pcnt == 2*zero_interval+1) {
-//                dsl_config_adc(sdi, adc_single_ch3);
-//                probe0->enabled = FALSE;
-//                probe1->enabled = TRUE;
-
-//                probe1->zero_offset = offset_bom;
-//                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
-//            }
-//            if (devc->zero_pcnt == 3*zero_interval) {
-//                margin[1] = offset[1] - (devc->mstatus.ch1_acc_mean * 1.0 / devc->limit_samples);
-//                if (fabs(margin[1]) > margin_pass) {
-//                    probe1->comb_comp -= margin[1] > 0 ? ceil(margin[1]) : floor(margin[1]);
-//                    ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
-//                    devc->zero_pcnt = 2*zero_interval+1;
-//                }
-//            }
-//            end_cnt = 3*zero_interval + 1;
-        } else {
-            if (devc->zero_pcnt == 0*zero_interval+1) {
-                ret = dsl_wr_reg(sdi, COMB_ADDR+6, 0b1101);
-                wr_cmd.header.dest = DSL_CTL_DSO_EN1;
-                wr_cmd.data[0] = (uint8_t)~bmCH_CH1;
-                wr_cmd.header.size = 1;
-                ret = command_ctl_wr(hdl, wr_cmd);
-
-                probe0->zero_offset = offset_top;
-                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
-            } else if (devc->zero_pcnt == 1*zero_interval) {
-                probe0->comb_diff_top = ((devc->mstatus.ch0_acc_mean * 2.0 - devc->mstatus.ch1_acc_mean * 2.0) / devc->limit_samples);
-                probe0->zero_offset = offset_bom;
-                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe0, SR_CONF_PROBE_OFFSET));
-            } else if (devc->zero_pcnt == 2*zero_interval) {
-                probe0->comb_diff_bom = ((devc->mstatus.ch0_acc_mean * 2.0 - devc->mstatus.ch1_acc_mean * 2.0) / devc->limit_samples);
-            }
-
-            if (devc->zero_pcnt == 2*zero_interval+1) {
-                ret = dsl_wr_reg(sdi, COMB_ADDR+6, 0b1110);
-                wr_cmd.header.dest = DSL_CTL_DSO_EN1;
-                wr_cmd.data[0] = bmCH_CH1;
-                wr_cmd.header.size = 1;
-                ret = command_ctl_wr(hdl, wr_cmd);
-                wr_cmd.header.dest = DSL_CTL_DSO_EN0;
-                wr_cmd.data[0] = (uint8_t)~bmCH_CH0;
-                wr_cmd.header.size = 1;
-                ret = command_ctl_wr(hdl, wr_cmd);
-
-                probe1->zero_offset = offset_top;
-                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
-            } else if (devc->zero_pcnt == 3*zero_interval) {
-                probe1->comb_diff_top = ((devc->mstatus.ch1_acc_mean * 2.0 - devc->mstatus.ch0_acc_mean * 2.0) / devc->limit_samples);
-                probe1->zero_offset = offset_bom;
-                ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe1, SR_CONF_PROBE_OFFSET));
-            } else if (devc->zero_pcnt == 4*zero_interval) {
-                probe1->comb_diff_bom = ((devc->mstatus.ch1_acc_mean * 2.0 - devc->mstatus.ch0_acc_mean * 2.0) / devc->limit_samples);
-            }
-
-            end_cnt = 4*zero_interval+1;
-        }
-
-        if (ret == SR_OK)
-            devc->zero_pcnt++;
-
-        if (devc->zero_pcnt == end_cnt) {
-            for(l = sdi->channels; l; l = l->next) {
-                struct sr_channel *probe = (struct sr_channel *)l->data;
-                probe->vdiv = vdiv_back[probe->index];
-//                if (!(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511))
-//                    probe->comb_comp = ((1 << channel_modes[devc->ch_mode].unit_bits) - 1) * 0.7 * 2 /
-//                                       min(abs(probe->comb_diff_top), abs(probe->comb_diff_bom));
-
-            }
-
-            ret = dsl_wr_reg(sdi, COMB_ADDR+6, 0b0011);
-            wr_cmd.header.dest = DSL_CTL_DSO_EN0;
-            wr_cmd.data[0] = bmCH_CH0;
-            wr_cmd.header.size = 1;
-            ret = command_ctl_wr(hdl, wr_cmd);
-            wr_cmd.header.dest = DSL_CTL_DSO_EN1;
-            wr_cmd.data[0] = bmCH_CH1;
-            wr_cmd.header.size = 1;
-            ret = command_ctl_wr(hdl, wr_cmd);
-
-            devc->zero = FALSE;
-            trans_fix_done = FALSE;
-            mid_zero_done = FALSE;
-            dso_init(sdi);
-        }
-    }
-
-    return ret;
-}
-
 static int dso_tune(const struct sr_dev_inst *sdi)
 {
     struct DSL_context *devc = sdi->priv;
@@ -1631,6 +1806,7 @@ static int dev_open(struct sr_dev_inst *sdi)
 static int dev_close(struct sr_dev_inst *sdi)
 {
     int ret;
+    dso_zero(sdi, TRUE);
     ret = dsl_dev_close(sdi);
     return ret;
 }
@@ -1667,23 +1843,45 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi)
     struct timeval tv;
     struct drv_context *drvc;
     struct DSL_context *devc;
+    struct ctl_rd_cmd rd_cmd;
+    struct sr_usb_dev_inst *usb;
+    int ret;
 
     (void)fd;
     (void)revents;
 
     drvc = di->priv;
     devc = sdi->priv;
+    usb = sdi->conn;
 
     tv.tv_sec = tv.tv_usec = 0;
     libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, &completed);
 
+    if (devc->trf_completed)
+        devc->empty_poll_count = 0;
+    else
+        devc->empty_poll_count++;
+
     if (devc->zero && devc->trf_completed) {
-        dso_zero(sdi);
+        dso_zero(sdi, FALSE);
     }
     if (devc->tune && devc->trf_completed) {
         dso_tune(sdi);
     }
 
+    // progress check
+    if ((devc->empty_poll_count > MAX_EMPTY_POLL) && (devc->status == DSL_START)) {
+        devc->mstatus.captured_cnt0 = 0;
+        rd_cmd.header.dest = DSL_CTL_I2C_STATUS;
+        rd_cmd.header.offset = 0;
+        rd_cmd.header.size = 4;
+        rd_cmd.data = (unsigned char*)&devc->mstatus;
+        if ((ret = command_ctl_rd(usb->devhdl, rd_cmd)) != SR_OK)
+            sr_err("Failed to get progress infos.");
+
+        devc->empty_poll_count = 0;
+    }
+
     if (devc->status == DSL_FINISH) {
         remove_sources(devc);
     }
@@ -1716,12 +1914,18 @@ static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data)
     devc->cb_data = sdi;
     devc->num_samples = 0;
     devc->empty_transfer_count = 0;
+    devc->empty_poll_count = 0;
     devc->status = DSL_INIT;
     devc->num_transfers = 0;
     devc->submitted_transfers = 0;
-    devc->actual_samples = (devc->limit_samples + 1023ULL) & ~1023ULL;
+    devc->actual_samples = (devc->limit_samples + SAMPLES_ALIGN) & ~SAMPLES_ALIGN;
 	devc->abort = FALSE;
     devc->mstatus_valid = FALSE;
+    devc->mstatus.captured_cnt0 = 0;
+    devc->mstatus.captured_cnt1 = 0;
+    devc->mstatus.captured_cnt2 = 0;
+    devc->mstatus.captured_cnt3 = 0;
+    devc->mstatus.trig_hit = 0;
     devc->overflow = FALSE;
     devc->instant_tail_bytes = dsl_header_size(devc);
 
@@ -1745,19 +1949,27 @@ static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data)
     if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_HMCAD1511) {
         if (dsl_en_ch_num(sdi) == 2) {
             dsl_config_adc(sdi, adc_dual_ch03);
+            for (l = sdi->channels; l; l = l->next) {
+                struct sr_channel *probe = (struct sr_channel *)l->data;
+                dsl_config_adc_fgain(sdi, probe->index*2 + 0, probe->cali_fgain0, probe->cali_fgain1);
+                dsl_config_adc_fgain(sdi, probe->index*2 + 1, probe->cali_fgain2, probe->cali_fgain3);
+            }
         } else if (dsl_en_ch_num(sdi) == 1) {
             for (l = sdi->channels; l; l = l->next) {
                 struct sr_channel *probe = (struct sr_channel *)l->data;
                 if (probe->enabled && probe->index == 0) {
                     dsl_config_adc(sdi, adc_single_ch0);
-                    break;
                 } else if (probe->enabled && probe->index == 1) {
                     dsl_config_adc(sdi, adc_single_ch3);
-                    break;
                 }
             }
+            for (l = sdi->channels; l; l = l->next) {
+                struct sr_channel *probe = (struct sr_channel *)l->data;
+                dsl_config_adc_fgain(sdi, probe->index*2 + 0, probe->cali_comb_fgain0, probe->cali_comb_fgain1);
+                dsl_config_adc_fgain(sdi, probe->index*2 + 1, probe->cali_comb_fgain2, probe->cali_comb_fgain3);
+            }
         }
-        //dsl_config_adc(sdi, adc_power_up);
+        dsl_config_fpga_fgain(sdi);
     }
     if ((ret = dsl_fpga_arm(sdi)) != SR_OK) {
         sr_err("%s: Arm FPGA failed!", __func__);
@@ -1771,12 +1983,14 @@ static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data)
             return ret;
         }
         devc->zero_stage = 0;
+        devc->zero_comb_fgain = FALSE;
+        devc->zero_branch = FALSE;
     }
 
     /*
      * settings must be updated before acquisition
      */
-    if (sdi->mode == DSO) {
+    if (sdi->mode != LOGIC) {
         devc->trigger_hpos =  devc->trigger_hrate * dsl_en_ch_num(sdi) * devc->limit_samples / 200.0;
         ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, NULL, SR_CONF_HORIZ_TRIGGERPOS));
         if (ret != SR_OK)
@@ -1790,6 +2004,7 @@ static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data)
             ret = dsl_wr_dso(sdi, dso_cmd_gen(sdi, probe, SR_CONF_PROBE_OFFSET));
             if (ret != SR_OK)
                 sr_err("%s: Set OFFSET of channel %d command failed!", __func__, probe->index);
+            probe->hw_offset = probe->offset;
         }
     }
 
@@ -1839,9 +2054,9 @@ static int dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data)
     return ret;
 }
 
-static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end)
+static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg)
 {
-    int ret = dsl_dev_status_get(sdi, status, prg, begin, end);
+    int ret = dsl_dev_status_get(sdi, status, prg);
     return ret;
 }
 
diff --git a/libsigrok4DSL/hardware/DSL/dsl.c b/libsigrok4DSL/hardware/DSL/dsl.c
index 40010a9c96454f249acf52fee72cb862779528e8..9e5628c9b2566e5a1e89e3097b70d759213edcb3 100755
--- a/libsigrok4DSL/hardware/DSL/dsl.c
+++ b/libsigrok4DSL/hardware/DSL/dsl.c
@@ -86,12 +86,20 @@ SR_PRIV void dsl_probe_init(struct sr_dev_inst *sdi)
         probe->bits = channel_modes[devc->ch_mode].unit_bits;
         probe->vdiv = 1000;
         probe->vfactor = 1;
+        probe->cali_fgain0 = 1;
+        probe->cali_fgain1 = 1;
+        probe->cali_fgain2 = 1;
+        probe->cali_fgain3 = 1;
+        probe->cali_comb_fgain0 = 1;
+        probe->cali_comb_fgain1 = 1;
+        probe->cali_comb_fgain2 = 1;
+        probe->cali_comb_fgain3 = 1;
         probe->offset = (1 << (probe->bits - 1));
-        probe->hw_offset = (1 << (probe->bits - 1));
         probe->coupling = SR_DC_COUPLING;
         probe->trig_value = (1 << (probe->bits - 1));
         probe->vpos_trans = devc->profile->dev_caps.default_pwmtrans;
         probe->comb_comp = devc->profile->dev_caps.default_comb_comp;
+        probe->digi_fgain = 0;
 
         probe->map_default = TRUE;
         probe->map_unit = probeMapUnits[0];
@@ -421,7 +429,7 @@ SR_PRIV uint64_t dsl_channel_depth(const struct sr_dev_inst *sdi)
 {
     struct DSL_context *devc = sdi->priv;
     int ch_num = dsl_en_ch_num(sdi);
-    return devc->profile->dev_caps.hw_depth / (ch_num ? ch_num : 1);
+    return (devc->profile->dev_caps.hw_depth / (ch_num ? ch_num : 1)) & ~SAMPLES_ALIGN;
 }
 
 SR_PRIV int dsl_wr_reg(const struct sr_dev_inst *sdi, uint8_t addr, uint8_t value)
@@ -675,6 +683,282 @@ SR_PRIV int dsl_config_adc(const struct sr_dev_inst *sdi, const struct DSL_adc_c
     return SR_OK;
 }
 
+SR_PRIV double dsl_adc_code2fgain(uint8_t code)
+{
+    double xcode = code & 0x40 ? -(~code & 0x3F) : code & 0x3F;
+    return (1 + xcode / (1 << 13));
+}
+
+SR_PRIV uint8_t dsl_adc_fgain2code(double gain)
+{
+    int xratio = (gain - 1) * (1 << 13);
+    uint8_t code = xratio > 63 ? 63 :
+                   xratio > 0 ? xratio :
+                   xratio < -63 ? 64 : ~(-xratio) & 0x7F;
+    return code;
+}
+
+SR_PRIV int dsl_config_adc_fgain(const struct sr_dev_inst *sdi, uint8_t branch, double gain0, double gain1)
+{
+    dsl_wr_reg(sdi, ADCC_ADDR, 0x00);
+    dsl_wr_reg(sdi, ADCC_ADDR, dsl_adc_fgain2code(gain0));
+    dsl_wr_reg(sdi, ADCC_ADDR, dsl_adc_fgain2code(gain1));
+    dsl_wr_reg(sdi, ADCC_ADDR, 0x34 + branch);
+
+    return SR_OK;
+}
+
+SR_PRIV int dsl_config_fpga_fgain(const struct sr_dev_inst *sdi)
+{
+    GSList *l;
+    int ret = SR_OK;
+
+    for (l = sdi->channels; l; l = l->next) {
+        struct sr_channel *probe = (struct sr_channel *)l->data;
+        if (probe->index == 0) {
+            ret = dsl_wr_reg(sdi, ADCC_ADDR+3, (probe->digi_fgain & 0x00FF));
+            ret = dsl_wr_reg(sdi, ADCC_ADDR+4, (probe->digi_fgain >> 8));
+        } else if (probe->index == 1) {
+            ret = dsl_wr_reg(sdi, ADCC_ADDR+5, (probe->digi_fgain & 0x00FF));
+            ret = dsl_wr_reg(sdi, ADCC_ADDR+6, (probe->digi_fgain >>8));
+        }
+    }
+
+    return ret;
+}
+
+SR_PRIV int dsl_skew_fpga_fgain(const struct sr_dev_inst *sdi, gboolean comb, double skew[])
+{
+    uint8_t fgain_up = 0;
+    uint8_t fgain_dn = 0;
+    GSList *l;
+    gboolean tmp;
+    int ret;
+
+    for (int i = 0; i <= 7; i++) {
+        tmp = (-skew[i] > 1.6*MAX_ACC_VARIANCE);
+        fgain_up += (tmp << i);
+    }
+
+    if (comb) {
+        for (l = sdi->channels; l; l = l->next) {
+            struct sr_channel *probe = (struct sr_channel *)l->data;
+            if (probe->index == 0) {
+                probe->digi_fgain |= (probe->digi_fgain & 0xFF00) + fgain_up;
+                fgain_up = (probe->digi_fgain & 0x00FF);
+                break;
+            }
+        }
+        ret = dsl_wr_reg(sdi, ADCC_ADDR+3, fgain_up);
+    } else {
+        for (l = sdi->channels; l; l = l->next) {
+            struct sr_channel *probe = (struct sr_channel *)l->data;
+            if (probe->index == 0) {
+                probe->digi_fgain |= (fgain_up << 8) + (probe->digi_fgain & 0x00FF);
+                fgain_up = (probe->digi_fgain>>8);
+                break;
+            }
+        }
+        ret = dsl_wr_reg(sdi, ADCC_ADDR+4, fgain_up);
+    }
+
+    for (int i = 0; i <= 7; i++) {
+        tmp = (skew[i] > 1.6*MAX_ACC_VARIANCE);
+        fgain_dn += (tmp << i);
+    }
+
+    if (comb) {
+        for (l = sdi->channels; l; l = l->next) {
+            struct sr_channel *probe = (struct sr_channel *)l->data;
+            if (probe->index == 1) {
+                probe->digi_fgain |= (probe->digi_fgain & 0xFF00) + fgain_dn;
+                fgain_dn = (probe->digi_fgain & 0x00FF);
+                break;
+            }
+        }
+        ret = dsl_wr_reg(sdi, ADCC_ADDR+5, fgain_dn);
+    } else {
+        for (l = sdi->channels; l; l = l->next) {
+            struct sr_channel *probe = (struct sr_channel *)l->data;
+            if (probe->index == 1) {
+                probe->digi_fgain |= (fgain_dn << 8) + (probe->digi_fgain & 0x00FF);
+                fgain_dn = (probe->digi_fgain>>8);
+                break;
+            }
+        }
+        ret = dsl_wr_reg(sdi, ADCC_ADDR+6, fgain_dn);
+    }
+
+    return ret;
+}
+
+SR_PRIV int dsl_probe_cali_fgain(struct DSL_context *devc, struct sr_channel *probe, double mean, gboolean comb, gboolean reset)
+{
+    const double UPGAIN = 1.0077;
+    const double DNGAIN = 0.9923;
+    const double MDGAIN = 1;
+    const double ignore_ratio = 2.0;
+    const double ratio = 2.0;
+    double drift;
+    if (reset) {
+        if (comb) {
+            probe->cali_comb_fgain0 = MDGAIN;
+            probe->cali_comb_fgain1 = MDGAIN;
+            probe->cali_comb_fgain2 = MDGAIN;
+            probe->cali_comb_fgain3 = MDGAIN;
+        } else {
+            probe->cali_fgain0 = MDGAIN;
+            probe->cali_fgain1 = MDGAIN;
+            probe->cali_fgain2 = MDGAIN;
+            probe->cali_fgain3 = MDGAIN;
+        }
+    } else {
+        if (comb) {
+            /*
+             * not consist with hmcad1511 datasheet
+             *
+             * byte order | acc_mean          | single channel branch (datasheet)
+             * 0            ch0_acc_mean        1 (0->cali_comb_fgain0)
+             * 1            ch1_acc_mean        6 (1->cali_comb_fgain1)
+             * 2            ch0_acc_mean_p1     2 (0->cali_comb_fgain1)
+             * 3            ch1_acc_mean_p1     5 (1->cali_comb_fgain0)
+             * 4            ch0_acc_mean_p2     8 (1->cali_comb_fgain3)
+             * 5            ch1_acc_mean_p2     3 (0->cali_comb_fgain2)
+             * 6            ch0_acc_mean_p3     7 (1->cali_comb_fgain2)
+             * 7            ch1_acc_mean_p3     4 (0->cali_comb_fgain3)
+             */
+            if (probe->index == 0) {
+                drift = (devc->mstatus.ch0_acc_mean / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain0 /= (1 + drift);
+                drift = (devc->mstatus.ch0_acc_mean_p1 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain1 /= (1 + drift);
+                drift = (devc->mstatus.ch1_acc_mean_p2 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain2 /= (1 + drift);
+                drift = (devc->mstatus.ch1_acc_mean_p3 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain3 /= (1 + drift);
+            } else {
+                drift = (devc->mstatus.ch1_acc_mean_p1 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain0 /= (1 + drift);
+                drift = (devc->mstatus.ch1_acc_mean / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain1 /= (1 + drift);
+                drift = (devc->mstatus.ch0_acc_mean_p3 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain2 /= (1 + drift);
+                drift = (devc->mstatus.ch0_acc_mean_p2 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_comb_fgain3 /= (1 + drift);
+            }
+
+            probe->cali_comb_fgain0 = max(min(probe->cali_comb_fgain0, UPGAIN), DNGAIN);
+            probe->cali_comb_fgain1 = max(min(probe->cali_comb_fgain1, UPGAIN), DNGAIN);
+            probe->cali_comb_fgain2 = max(min(probe->cali_comb_fgain2, UPGAIN), DNGAIN);
+            probe->cali_comb_fgain3 = max(min(probe->cali_comb_fgain3, UPGAIN), DNGAIN);
+        } else {
+            /*
+             * byte order | acc_mean          | dual channel branch
+             * 0            ch0_acc_mean        1 (0->cali_fgain0)
+             * 1            ch0_acc_mean_p1     3 (0->cali_fgain2)
+             * 2            ch0_acc_mean_p2     2 (0->cali_fgain1)
+             * 3            ch0_acc_mean_p3     4 (0->cali_fgain3)
+             * 4            ch1_acc_mean        5 (1->cali_fgain0)
+             * 5            ch1_acc_mean_p1     7 (1->cali_fgain2)
+             * 6            ch1_acc_mean_p2     6 (1->cali_fgain1)
+             * 7            ch1_acc_mean_p3     8 (1->cali_fgain3)
+             */
+            if (probe->index == 0) {
+                drift = (devc->mstatus.ch0_acc_mean / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain0 /= (1 + drift);
+                drift = (devc->mstatus.ch0_acc_mean_p2 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain1 /= (1 + drift);
+                drift = (devc->mstatus.ch0_acc_mean_p1 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain2 /= (1 + drift);
+                drift = (devc->mstatus.ch0_acc_mean_p3 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain3 /= (1 + drift);
+            } else {
+                drift = (devc->mstatus.ch1_acc_mean / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain0 /= (1 + drift);
+                drift = (devc->mstatus.ch1_acc_mean_p2 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain1 /= (1 + drift);
+                drift = (devc->mstatus.ch1_acc_mean_p1 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain2 /= (1 + drift);
+                drift = (devc->mstatus.ch1_acc_mean_p3 / mean - 1) / ratio;
+                if (fabs(drift) > MAX_ACC_VARIANCE / ignore_ratio)
+                    probe->cali_fgain3 /= (1 + drift);
+            }
+
+            probe->cali_fgain0 = max(min(probe->cali_fgain0, UPGAIN), DNGAIN);
+            probe->cali_fgain1 = max(min(probe->cali_fgain1, UPGAIN), DNGAIN);
+            probe->cali_fgain2 = max(min(probe->cali_fgain2, UPGAIN), DNGAIN);
+            probe->cali_fgain3 = max(min(probe->cali_fgain3, UPGAIN), DNGAIN);
+        }
+    }
+
+    return SR_OK;
+}
+
+SR_PRIV gboolean dsl_probe_fgain_inrange(struct sr_channel *probe, gboolean comb, double skew[])
+{
+    const double UPGAIN = 1.0077;
+    const double DNGAIN = 0.9923;
+
+    if (comb) {
+        if (probe->index == 0) {
+            if (fabs(skew[0]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain0 > DNGAIN && probe->cali_comb_fgain0 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[1]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain1 > DNGAIN && probe->cali_comb_fgain1 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[6]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain2 > DNGAIN && probe->cali_comb_fgain2 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[7]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain3 > DNGAIN && probe->cali_comb_fgain3 < UPGAIN)
+                return TRUE;
+        } else {
+            if (fabs(skew[5]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain0 > DNGAIN && probe->cali_comb_fgain0 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[4]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain1 > DNGAIN && probe->cali_comb_fgain1 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[3]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain2 > DNGAIN && probe->cali_comb_fgain2 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[2]) > MAX_ACC_VARIANCE && probe->cali_comb_fgain3 > DNGAIN && probe->cali_comb_fgain3 < UPGAIN)
+                return TRUE;
+        }
+    } else {
+        if (probe->index == 0) {
+            if (fabs(skew[0]) > MAX_ACC_VARIANCE && probe->cali_fgain0 > DNGAIN && probe->cali_fgain0 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[2]) > MAX_ACC_VARIANCE && probe->cali_fgain1 > DNGAIN && probe->cali_fgain1 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[1]) > MAX_ACC_VARIANCE && probe->cali_fgain2 > DNGAIN && probe->cali_fgain2 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[3]) > MAX_ACC_VARIANCE && probe->cali_fgain3 > DNGAIN && probe->cali_fgain3 < UPGAIN)
+                return TRUE;
+        } else {
+            if (fabs(skew[4]) > MAX_ACC_VARIANCE && probe->cali_fgain0 > DNGAIN && probe->cali_fgain0 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[6]) > MAX_ACC_VARIANCE && probe->cali_fgain1 > DNGAIN && probe->cali_fgain1 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[5]) > MAX_ACC_VARIANCE && probe->cali_fgain2 > DNGAIN && probe->cali_fgain2 < UPGAIN)
+                return TRUE;
+            if (fabs(skew[7]) > MAX_ACC_VARIANCE && probe->cali_fgain3 > DNGAIN && probe->cali_fgain3 < UPGAIN)
+                return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 SR_PRIV int dsl_rd_probe(const struct sr_dev_inst *sdi, unsigned char *ctx, uint16_t addr, uint8_t len)
 {
     struct sr_usb_dev_inst *usb;
@@ -802,6 +1086,13 @@ SR_PRIV int dsl_fpga_arm(const struct sr_dev_inst *sdi)
             setting.ch_en_h += probe->enabled << (probe->index - 16);
     }
 
+    // digital fgain
+    for (l = sdi->channels; l; l = l->next) {
+        struct sr_channel *probe = (struct sr_channel *)l->data;
+        setting.fgain = probe->digi_fgain;
+        break;
+    }
+
     // trigger advanced configuration
     if (trigger->trigger_mode == SIMPLE_TRIGGER) {
         qutr_trig = !(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_USB30) && (setting.mode & (1 << QUAR_MODE_BIT));
@@ -1156,7 +1447,7 @@ SR_PRIV int dsl_config_get(int id, GVariant **data, const struct sr_dev_inst *sd
     case SR_CONF_USB30_SUPPORT:
         if (!sdi)
             return SR_ERR;
-        *data = g_variant_new_boolean(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_USB30);
+        *data = g_variant_new_boolean((devc->profile->dev_caps.feature_caps & CAPS_FEATURE_USB30) != 0);
         break;
     case SR_CONF_LIMIT_SAMPLES:
         if (!sdi)
@@ -1171,7 +1462,10 @@ SR_PRIV int dsl_config_get(int id, GVariant **data, const struct sr_dev_inst *sd
     case SR_CONF_RLE_SUPPORT:
         if (!sdi)
             return SR_ERR;
-        *data = g_variant_new_boolean(devc->rle_support);
+        if ((devc->test_mode != SR_TEST_NONE))
+            *data = g_variant_new_boolean(FALSE);
+        else
+            *data = g_variant_new_boolean(devc->rle_support);
         break;
     case SR_CONF_CLOCK_TYPE:
         if (!sdi)
@@ -1280,7 +1574,7 @@ SR_PRIV int dsl_config_get(int id, GVariant **data, const struct sr_dev_inst *sd
     case SR_CONF_HAVE_ZERO:
         if (!sdi)
             return SR_ERR;
-        *data = g_variant_new_boolean(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_ZERO);
+        *data = g_variant_new_boolean((devc->profile->dev_caps.feature_caps & CAPS_FEATURE_ZERO) != 0);
         break;
     case SR_CONF_ZERO:
         if (!sdi)
@@ -1290,6 +1584,11 @@ SR_PRIV int dsl_config_get(int id, GVariant **data, const struct sr_dev_inst *sd
         else
             *data = g_variant_new_boolean(FALSE);
         break;
+    case SR_CONF_ZERO_COMB_FGAIN:
+        if (!sdi)
+            return SR_ERR;
+        *data = g_variant_new_boolean(devc->zero_comb_fgain);
+        break;
     case SR_CONF_ROLL:
         if (!sdi)
             return SR_ERR;
@@ -1362,6 +1661,8 @@ SR_PRIV int dsl_config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
 
     if (id == SR_CONF_LANGUAGE) {
         devc->language = g_variant_get_int16(data);
+    } else if (id == SR_CONF_ZERO_COMB) {
+        devc->zero_comb = g_variant_get_boolean(data);
     } else if (id == SR_CONF_PROBE_MAP_DEFAULT) {
         ch->map_default = g_variant_get_boolean(data);
         if (ch->map_default) {
@@ -1579,24 +1880,14 @@ SR_PRIV int dsl_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_dat
     return SR_OK;
 }
 
-SR_PRIV int dsl_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end)
+SR_PRIV int dsl_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg)
 {
     int ret = SR_ERR;
-    struct ctl_rd_cmd rd_cmd;
 
     if (sdi) {
         struct DSL_context *devc;
-        struct sr_usb_dev_inst *usb;
-
         devc = sdi->priv;
-        usb = sdi->conn;
-        if (prg && (devc->status == DSL_START)) {
-            rd_cmd.header.dest = DSL_CTL_I2C_STATUS;
-            rd_cmd.header.offset = begin;
-            rd_cmd.header.size = end - begin + 1;
-            rd_cmd.data = (unsigned char*)status;
-            ret = command_ctl_rd(usb->devhdl, rd_cmd);
-        } else if (devc->mstatus_valid) {
+        if (prg || devc->mstatus_valid) {
             *status = devc->mstatus;
             ret = SR_OK;
         }
@@ -1630,7 +1921,7 @@ static unsigned int to_bytes_per_ms(struct DSL_context *devc)
         if (devc->cur_samplerate > SR_MHZ(100))
             return SR_MHZ(100) / 1000.0 * dsl_en_ch_num(sdi);
         else
-            return ceil(devc->cur_samplerate / 1000.0 * dsl_en_ch_num(sdi));
+            return ceil(max(devc->cur_samplerate, channel_modes[devc->ch_mode].hw_min_samplerate) / 1000.0 * dsl_en_ch_num(sdi));
     }
 }
 
@@ -1638,7 +1929,7 @@ SR_PRIV int dsl_header_size(const struct DSL_context *devc)
 {
     int size;
 
-    if (devc->profile->usb_speed == LIBUSB_SPEED_SUPER)
+    if (devc->profile->dev_caps.feature_caps & CAPS_FEATURE_USB30)
         size = SR_KB(1);
     else
         size = SR_B(512);
@@ -1660,7 +1951,11 @@ static size_t get_buffer_size(const struct sr_dev_inst *sdi)
     } else {
         s = (devc->stream) ? get_single_buffer_time(devc) * to_bytes_per_ms(devc) : 1024*1024;
     }
-    return (s + 511ULL) & ~511ULL;
+
+    if (devc->profile->usb_speed == LIBUSB_SPEED_SUPER)
+        return (s + 1023ULL) & ~1023ULL;
+    else
+        return (s + 511ULL) & ~511ULL;
 }
 
 static unsigned int get_number_of_transfers(const struct sr_dev_inst *sdi)
@@ -1673,7 +1968,8 @@ static unsigned int get_number_of_transfers(const struct sr_dev_inst *sdi)
     /* Total buffer size should be able to hold about 100ms of data. */
     n = (devc->stream) ? ceil(get_total_buffer_time(devc) * 1.0f * to_bytes_per_ms(devc) / get_buffer_size(sdi)) : 1;
     #else
-    n = (devc->stream) ? ceil(get_total_buffer_time(devc) * 1.0f * to_bytes_per_ms(devc) / get_buffer_size(sdi)) : 4;
+    n = (devc->stream) ? ceil(get_total_buffer_time(devc) * 1.0f * to_bytes_per_ms(devc) / get_buffer_size(sdi)) :
+        (devc->profile->usb_speed == LIBUSB_SPEED_SUPER) ? 16 : 4;
     #endif
 
     if (n > NUM_SIMUL_TRANSFERS)
@@ -1695,7 +1991,7 @@ SR_PRIV unsigned int dsl_get_timeout(const struct sr_dev_inst *sdi)
     if (devc->stream)
         return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
     else
-        return 1000;
+        return 20;
 }
 
 static void finish_acquisition(struct DSL_context *devc)
@@ -1756,6 +2052,7 @@ static void get_measure(const struct sr_dev_inst *sdi, uint8_t *buf, uint32_t of
 {
     uint64_t u64_tmp;
     struct DSL_context *devc = sdi->priv;
+    GSList *l;
 
     devc->mstatus.pkt_id = *((const uint16_t*)buf + offset);
     devc->mstatus.vlen = *((const uint32_t*)buf + offset/2 + 2/2) & 0x0fffffff;
@@ -1779,8 +2076,11 @@ static void get_measure(const struct sr_dev_inst *sdi, uint8_t *buf, uint32_t of
     devc->mstatus.ch0_low_level = *((const uint8_t*)buf + offset*2 + 43*2+1);
     devc->mstatus.ch0_cyc_rlen = *((const uint32_t*)buf + offset/2 + 44/2);
     devc->mstatus.ch0_cyc_flen = *((const uint32_t*)buf + offset/2 + 46/2);
-    devc->mstatus.ch0_acc_square = *((const uint64_t*)buf + offset/4 + 48/4);
+    devc->mstatus.ch0_acc_square = *((const uint64_t*)buf + offset/4 + 48/4) & 0x0000FFFFFFFFFFFF;
     devc->mstatus.ch0_acc_mean = *((const uint32_t*)buf + offset/2 + 52/2);
+    devc->mstatus.ch0_acc_mean_p1 = *((const uint32_t*)buf + offset/2 + 54/2);
+    devc->mstatus.ch0_acc_mean_p2 = *((const uint32_t*)buf + offset/2 + 56/2);
+    devc->mstatus.ch0_acc_mean_p3 = *((const uint32_t*)buf + offset/2 + 58/2);
 
     devc->mstatus.ch1_max = *((const uint8_t*)buf + offset*2 + 65*2);
     devc->mstatus.ch1_min = *((const uint8_t*)buf + offset*2 + 65*2+1);
@@ -1794,16 +2094,46 @@ static void get_measure(const struct sr_dev_inst *sdi, uint8_t *buf, uint32_t of
     devc->mstatus.ch1_low_level = *((const uint8_t*)buf + offset*2 + 75*2+1);
     devc->mstatus.ch1_cyc_rlen = *((const uint32_t*)buf + offset/2 + 76/2);
     devc->mstatus.ch1_cyc_flen = *((const uint32_t*)buf + offset/2 + 78/2);
-    devc->mstatus.ch1_acc_square = *((const uint64_t*)buf + offset/4 + 80/4);
+    devc->mstatus.ch1_acc_square = *((const uint64_t*)buf + offset/4 + 80/4) & 0x0000FFFFFFFFFFFF;
     devc->mstatus.ch1_acc_mean = *((const uint32_t*)buf + offset/2 + 84/2);
+    devc->mstatus.ch1_acc_mean_p1 = *((const uint32_t*)buf + offset/2 + 86/2);
+    devc->mstatus.ch1_acc_mean_p2 = *((const uint32_t*)buf + offset/2 + 88/2);
+    devc->mstatus.ch1_acc_mean_p3 = *((const uint32_t*)buf + offset/2 + 90/2);
+
+    if (!devc->zero_branch) {
+        devc->mstatus.ch0_acc_mean += devc->mstatus.ch0_acc_mean_p1;
+        devc->mstatus.ch0_acc_mean += devc->mstatus.ch0_acc_mean_p2;
+        devc->mstatus.ch0_acc_mean += devc->mstatus.ch0_acc_mean_p3;
+
+        devc->mstatus.ch1_acc_mean += devc->mstatus.ch1_acc_mean_p1;
+        devc->mstatus.ch1_acc_mean += devc->mstatus.ch1_acc_mean_p2;
+        devc->mstatus.ch1_acc_mean += devc->mstatus.ch1_acc_mean_p3;
+
+        if (1 == dsl_en_ch_num(sdi)) {
+            u64_tmp = devc->mstatus.ch0_acc_square + devc->mstatus.ch1_acc_square;
+            devc->mstatus.ch0_acc_square = u64_tmp;
+            devc->mstatus.ch1_acc_square = u64_tmp;
+            u64_tmp = devc->mstatus.ch0_acc_mean + devc->mstatus.ch1_acc_mean;
+            devc->mstatus.ch0_acc_mean = u64_tmp;
+            devc->mstatus.ch1_acc_mean = u64_tmp;
+        }
+    }
+
+    devc->mstatus_valid = FALSE;
+    const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(channel_modes[devc->ch_mode].max_samplerate * 1.0 / devc->cur_samplerate / dsl_en_ch_num(sdi));
+    if (devc->instant) {
+        devc->mstatus_valid = (devc->mstatus.pkt_id == DSO_PKTID);
+    } else if (devc->mstatus.pkt_id == DSO_PKTID &&
+               devc->mstatus.sample_divider == divider &&
+               devc->mstatus.vlen != 0) {
+        devc->mstatus_valid = TRUE;
+    }
 
-    if (1 == dsl_en_ch_num(sdi)) {
-        u64_tmp = devc->mstatus.ch0_acc_square + devc->mstatus.ch1_acc_square;
-        devc->mstatus.ch0_acc_square = u64_tmp;
-        devc->mstatus.ch1_acc_square = u64_tmp;
-        u64_tmp = devc->mstatus.ch0_acc_mean + devc->mstatus.ch1_acc_mean;
-        devc->mstatus.ch0_acc_mean = u64_tmp;
-        devc->mstatus.ch0_acc_mean = u64_tmp;
+    if (devc->mstatus_valid) {
+        for (l = sdi->channels; l; l = l->next) {
+            struct sr_channel *probe = (struct sr_channel *)l->data;
+            probe->hw_offset = *((const uint8_t*)buf + offset*2 + (51 + 32*probe->index)*2);
+        }
     }
 }
 
@@ -1856,16 +2186,13 @@ static void receive_transfer(struct libusb_transfer *transfer)
                 get_measure(sdi, cur_buf, offset);
             } else {
                 devc->mstatus.vlen = get_buffer_size(sdi) / channel_modes[devc->ch_mode].num;
+                devc->mstatus.trig_offset = 0;
+                devc->mstatus.sample_divider_tog = FALSE;
+                devc->mstatus_valid = TRUE;
             }
 
-            const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(channel_modes[devc->ch_mode].max_samplerate * 1.0 / devc->cur_samplerate / dsl_en_ch_num(sdi));
-            if ((devc->mstatus.pkt_id == DSO_PKTID &&
-                 devc->mstatus.sample_divider == divider &&
-                 devc->mstatus.vlen != 0 &&
-                 devc->mstatus.vlen <= (uint32_t)(transfer->actual_length - dsl_header_size(devc)) / 2) ||
-                devc->instant) {
+            if (devc->mstatus_valid) {
                 devc->roll = (devc->mstatus.stream_mode != 0);
-                devc->mstatus_valid = devc->instant ? FALSE : TRUE;
                 packet.type = SR_DF_DSO;
                 packet.payload = &dso;
                 dso.probes = sdi->channels;
@@ -1876,11 +2203,11 @@ static void receive_transfer(struct libusb_transfer *transfer)
                 dso.mqflags = SR_MQFLAG_AC;
                 dso.samplerate_tog = (devc->mstatus.sample_divider_tog != 0);
                 dso.trig_flag = (devc->mstatus.trig_flag != 0);
-                dso.data = cur_buf;
+                dso.trig_ch = devc->mstatus.trig_ch;
+                dso.data = cur_buf + (devc->zero ? 0 : 2*devc->mstatus.trig_offset);
             } else {
                 packet.type = SR_DF_DSO;
                 packet.status = SR_PKT_DATA_ERROR;
-                devc->mstatus_valid = FALSE;
             }
         } else if (sdi->mode == ANALOG) {
             packet.type = SR_DF_ANALOG;
@@ -1902,14 +2229,8 @@ static void receive_transfer(struct libusb_transfer *transfer)
             logic.length = min(logic.length, remain_length);
 
             /* send data to session bus */
-            if (!devc->overflow) {
-                if (packet.status == SR_PKT_OK)
-                    sr_session_send(sdi, &packet);
-            } else {
-                packet.type = SR_DF_OVERFLOW;
-                packet.payload = NULL;
+            if (packet.status == SR_PKT_OK)
                 sr_session_send(sdi, &packet);
-            }
         }
 
         devc->num_samples += cur_sample_count;
@@ -1925,8 +2246,6 @@ static void receive_transfer(struct libusb_transfer *transfer)
             if (over_bytes >= devc->instant_tail_bytes) {
                 const uint32_t offset = (transfer->actual_length - over_bytes) / 2;
                 get_measure(sdi, cur_buf, offset);
-                if (devc->mstatus.pkt_id == DSO_PKTID)
-                    devc->mstatus_valid = TRUE;
                 devc->status = DSL_STOP;
             } else {
 
@@ -1968,7 +2287,7 @@ static void receive_header(struct libusb_transfer *transfer)
                 devc->stream ||
                 remain_cnt < devc->limit_samples) {
                 if (sdi->mode == LOGIC && (!devc->stream || (devc->status == DSL_ABORT))) {
-                    devc->actual_samples = devc->limit_samples - remain_cnt;
+                    devc->actual_samples = (devc->limit_samples - remain_cnt) & ~SAMPLES_ALIGN;
                     devc->actual_bytes = devc->actual_samples / DSLOGIC_ATOMIC_SAMPLES * dsl_en_ch_num(sdi) * DSLOGIC_ATOMIC_SIZE;
                     devc->actual_samples = devc->actual_bytes / dsl_en_ch_num(sdi) * 8;
                 }
diff --git a/libsigrok4DSL/hardware/DSL/dsl.h b/libsigrok4DSL/hardware/DSL/dsl.h
index 2376784217e132186d1ed9ac729bdede50ad81ef..a30e7a94c18acc56266cf0512d9cd8b121477df5 100755
--- a/libsigrok4DSL/hardware/DSL/dsl.h
+++ b/libsigrok4DSL/hardware/DSL/dsl.h
@@ -54,6 +54,7 @@
 #define USB_CONFIGURATION	1
 #define NUM_TRIGGER_STAGES	16
 #define NUM_SIMUL_TRANSFERS	64
+#define MAX_EMPTY_POLL      16
 
 #define DSL_REQUIRED_VERSION_MAJOR	2
 #define DSL_REQUIRED_VERSION_MINOR	0
@@ -132,6 +133,11 @@
 #define TRIG_CHECKID 0x55555555
 #define DSO_PKTID 0xa500
 
+/*
+ * zero configuration
+ */
+#define DSO_ZERO_PAGE 8
+#define MAX_ACC_VARIANCE 0.0005
 /*
  * for DSCope device
  * trans: x << 8 + y
@@ -341,14 +347,14 @@ static const struct DSL_vga vga_defaults[] = {
     {3, 1000, 0x57200,  45, 1024-920-45},
     {3, 2000, 0x2DD00,  45, 1024-920-45},
 
-    {4, 10,   0x1C6C00, 45, 1024-945-45},
-    {4, 20,   0x19E000, 45, 1024-945-45},
-    {4, 50,   0x16A800, 45, 1024-945-45},
-    {4, 100,  0x142800, 45, 1024-945-45},
-    {4, 200,  0xC7F00,  45, 1024-945-45},
-    {4, 500,  0x94000,  45, 1024-945-45},
-    {4, 1000, 0x6CF00,  45, 1024-945-45},
-    {4, 2000, 0x44F00,  45, 1024-945-45},
+    {4, 10,   0x1C6C00, 60, 1024-900-60},
+    {4, 20,   0x19E000, 60, 1024-900-60},
+    {4, 50,   0x16A800, 60, 1024-900-60},
+    {4, 100,  0x142800, 60, 1024-900-60},
+    {4, 200,  0xC7F00,  60, 1024-900-60},
+    {4, 500,  0x94000,  60, 1024-900-60},
+    {4, 1000, 0x6CF00,  60, 1024-900-60},
+    {4, 2000, 0x44F00,  60, 1024-900-60},
 
     {0, 0, 0, 0, 0}
 };
@@ -358,19 +364,36 @@ enum CHANNEL_ID {
     DSL_STREAM25x12,
     DSL_STREAM50x6,
     DSL_STREAM100x3,
-    DSL_STREAM100x16,
-    DSL_STREAM125x16,
+
+    DSL_STREAM20x16_3DN2,
+    DSL_STREAM25x12_3DN2,
+    DSL_STREAM50x6_3DN2,
+    DSL_STREAM100x3_3DN2,
+
+    DSL_STREAM10x32_32_3DN2,
+    DSL_STREAM20x16_32_3DN2,
+    DSL_STREAM25x12_32_3DN2,
+    DSL_STREAM50x6_32_3DN2,
+    DSL_STREAM100x3_32_3DN2,
+
+    DSL_STREAM50x32,
+    DSL_STREAM100x30,
     DSL_STREAM250x12,
+    DSL_STREAM125x16_16,
+    DSL_STREAM250x12_16,
     DSL_STREAM500x6,
     DSL_STREAM1000x3,
 
     DSL_BUFFER100x16,
     DSL_BUFFER200x8,
     DSL_BUFFER400x4,
+
+    DSL_BUFFER250x32,
     DSL_BUFFER500x16,
     DSL_BUFFER1000x8,
 
     DSL_ANALOG10x2,
+    DSL_ANALOG10x2_500,
 
     DSL_DSO200x2,
     DSL_DSO1000x2,
@@ -403,15 +426,40 @@ static const struct DSL_channels channel_modes[] = {
      SR_KHZ(10), SR_MHZ(100), 1, "Use 6 Channels (Max 50MHz)", "使用6个通道(最大采样率 50MHz)"},
     {DSL_STREAM100x3,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE,  16, 3,  1, SR_KHZ(10), SR_MHZ(100),
      SR_KHZ(10), SR_MHZ(100), 1, "Use 3 Channels (Max 100MHz)", "使用3个通道(最大采样率 100MHz)"},
-    {DSL_STREAM100x16,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 16, 1, SR_KHZ(10), SR_MHZ(100),
-     SR_KHZ(10), SR_MHZ(500), 5, "Use 16 Channels (Max 100MHz)", "使用16个通道(最大采样率 100MHz)"},
-    {DSL_STREAM125x16,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 16, 1, SR_KHZ(10), SR_MHZ(125),
+
+    {DSL_STREAM20x16_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 16, 1, SR_KHZ(10), SR_MHZ(20),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 16 Channels (Max 20MHz)", "使用16个通道(最大采样率 20MHz)"},
+    {DSL_STREAM25x12_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 12, 1, SR_KHZ(10), SR_MHZ(25),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 12 Channels (Max 25MHz)", "使用12个通道(最大采样率 25MHz)"},
+    {DSL_STREAM50x6_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 6, 1, SR_KHZ(10), SR_MHZ(50),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 6 Channels (Max 50MHz)", "使用6个通道(最大采样率 50MHz)"},
+    {DSL_STREAM100x3_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 3, 1, SR_KHZ(10), SR_MHZ(100),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 3 Channels (Max 100MHz)", "使用3个通道(最大采样率 100MHz)"},
+
+    {DSL_STREAM10x32_32_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 32, 1, SR_KHZ(10), SR_MHZ(10),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 32 Channels (Max 10MHz)", "使用32个通道(最大采样率 10MHz)"},
+    {DSL_STREAM20x16_32_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 16, 1, SR_KHZ(10), SR_MHZ(20),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 16 Channels (Max 20MHz)", "使用16个通道(最大采样率 20MHz)"},
+    {DSL_STREAM25x12_32_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 12, 1, SR_KHZ(10), SR_MHZ(25),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 12 Channels (Max 25MHz)", "使用12个通道(最大采样率 25MHz)"},
+    {DSL_STREAM50x6_32_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 6, 1, SR_KHZ(10), SR_MHZ(50),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 6 Channels (Max 50MHz)", "使用6个通道(最大采样率 50MHz)"},
+    {DSL_STREAM100x3_32_3DN2,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 3, 1, SR_KHZ(10), SR_MHZ(100),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 3 Channels (Max 100MHz)", "使用3个通道(最大采样率 100MHz)"},
+
+    {DSL_STREAM50x32,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 32, 1, SR_KHZ(10), SR_MHZ(50),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 32 Channels (Max 50MHz)", "使用32个通道(最大采样率 50MHz)"},
+    {DSL_STREAM100x30,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 30, 1, SR_KHZ(10), SR_MHZ(100),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 30 Channels (Max 100MHz)", "使用30个通道(最大采样率 100MHz)"},
+    {DSL_STREAM250x12,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 32, 12, 1, SR_KHZ(10), SR_MHZ(250),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use 12 Channels (Max 250MHz)", "使用12个通道(最大采样率 250MHz)"},
+    {DSL_STREAM125x16_16,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 16, 1, SR_KHZ(10), SR_MHZ(125),
      SR_KHZ(10), SR_MHZ(500), 5, "Use 16 Channels (Max 125MHz)", "使用16个通道(最大采样率 125MHz)"},
-    {DSL_STREAM250x12,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 12, 1, SR_KHZ(10), SR_MHZ(250),
+    {DSL_STREAM250x12_16,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 12, 1, SR_KHZ(10), SR_MHZ(250),
      SR_KHZ(10), SR_MHZ(500), 5, "Use 12 Channels (Max 250MHz)", "使用12个通道(最大采样率 250MHz)"},
     {DSL_STREAM500x6,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE,  16, 6,  1, SR_KHZ(10), SR_MHZ(500),
      SR_KHZ(10), SR_MHZ(500), 5, "Use 6 Channels (Max 500MHz)", "使用6个通道(最大采样率 500MHz)"},
-    {DSL_STREAM1000x3,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 16, 3,  1, SR_KHZ(10), SR_GHZ(1),
+    {DSL_STREAM1000x3,  LOGIC,  SR_CHANNEL_LOGIC,  TRUE, 8, 3,  1, SR_KHZ(10), SR_GHZ(1),
      SR_KHZ(10), SR_MHZ(500), 5, "Use 3 Channels (Max 1GHz)", "使用3个通道(最大采样率 1GHz)"},
 
     // LA Buffer
@@ -421,6 +469,9 @@ static const struct DSL_channels channel_modes[] = {
      SR_KHZ(10), SR_MHZ(100), 1, "Use Channels 0~7 (Max 200MHz)", "使用通道 0~7 (最大采样率 200MHz)"},
     {DSL_BUFFER400x4,  LOGIC,  SR_CHANNEL_LOGIC,  FALSE, 4, 4,  1, SR_KHZ(10), SR_MHZ(400),
      SR_KHZ(10), SR_MHZ(100), 1, "Use Channels 0~3 (Max 400MHz)", "使用通道 0~3 (最大采样率 400MHz)"},
+
+    {DSL_BUFFER250x32,  LOGIC,  SR_CHANNEL_LOGIC,  FALSE, 32, 32,  1, SR_KHZ(10), SR_MHZ(250),
+     SR_KHZ(10), SR_MHZ(500), 5, "Use Channels 0~31 (Max 250MHz)", "使用通道 0~31 (最大采样率 250MHz)"},
     {DSL_BUFFER500x16,  LOGIC,  SR_CHANNEL_LOGIC,  FALSE, 16, 16,  1, SR_KHZ(10), SR_MHZ(500),
      SR_KHZ(10), SR_MHZ(500), 5, "Use Channels 0~15 (Max 500MHz)", "使用通道 0~15 (最大采样率 500MHz)"},
     {DSL_BUFFER1000x8,  LOGIC,  SR_CHANNEL_LOGIC,  FALSE, 8, 8,  1, SR_KHZ(10), SR_GHZ(1),
@@ -429,12 +480,14 @@ static const struct DSL_channels channel_modes[] = {
     // DAQ
     {DSL_ANALOG10x2,   ANALOG, SR_CHANNEL_ANALOG, TRUE,  2, 2,  8, SR_HZ(10),  SR_MHZ(10),
      SR_KHZ(10), SR_MHZ(100), 1, "Use Channels 0~1 (Max 10MHz)", "使用通道 0~1 (最大采样率 10MHz)"},
+    {DSL_ANALOG10x2_500,   ANALOG, SR_CHANNEL_ANALOG, TRUE,  2, 2,  8, SR_HZ(10),  SR_MHZ(10),
+     SR_KHZ(10), SR_MHZ(500), 1, "Use Channels 0~1 (Max 10MHz)", "使用通道 0~1 (最大采样率 10MHz)"},
 
     // OSC
     {DSL_DSO200x2,     DSO,    SR_CHANNEL_DSO,    FALSE, 2, 2,  8, SR_KHZ(10), SR_MHZ(200),
      SR_KHZ(10), SR_MHZ(100), 1, "Use Channels 0~1 (Max 200MHz)", "使用通道 0~1 (最大采样率 200MHz)"},
     {DSL_DSO1000x2,    DSO,    SR_CHANNEL_DSO,    FALSE, 2, 2,  8, SR_KHZ(10), SR_GHZ(1),
-     SR_KHZ(10), SR_MHZ(100), 1, "Use Channels 0~1 (Max 1GHz)", "使用通道 0~1 (最大采样率 1GHz)"}
+     SR_KHZ(10), SR_MHZ(500), 1, "Use Channels 0~1 (Max 1GHz)", "使用通道 0~1 (最大采样率 1GHz)"}
 };
 
 static const struct DSL_profile supported_DSLogic[] = {
@@ -578,6 +631,114 @@ static const struct DSL_profile supported_DSLogic[] = {
       SR_MHZ(400)}
     },
 
+    {0x2A0E, 0x002A, LIBUSB_SPEED_HIGH, "DreamSourceLab", "DSLogic U3Pro16", NULL,
+     "DSLogicU3Pro16.fw",
+     "DSLogicU3Pro16.bin",
+     "DSLogicU3Pro16.bin",
+     {CAPS_MODE_LOGIC,
+      CAPS_FEATURE_VTH | CAPS_FEATURE_BUF | CAPS_FEATURE_USB30  | CAPS_FEATURE_ADF4360,
+      (1 << DSL_STREAM20x16_3DN2) | (1 << DSL_STREAM25x12_3DN2) | (1 << DSL_STREAM50x6_3DN2) | (1 << DSL_STREAM100x3_3DN2) |
+      (1 << DSL_BUFFER500x16) | (1 << DSL_BUFFER1000x8),
+      16,
+      SR_GB(2),
+      0,
+      DSL_BUFFER500x16,
+      0,
+      samplerates1000,
+      0,
+      DSL_STREAM20x16_3DN2,
+      SR_MHZ(1),
+      SR_Mn(1),
+      0,
+      0,
+      0,
+      0,
+      0,
+      SR_MHZ(500),
+      SR_GHZ(1)}
+    },
+
+    {0x2A0E, 0x002A, LIBUSB_SPEED_SUPER, "DreamSourceLab", "DSLogic U3Pro16", NULL,
+     "DSLogicU3Pro16.fw",
+     "DSLogicU3Pro16.bin",
+     "DSLogicU3Pro16.bin",
+     {CAPS_MODE_LOGIC,
+      CAPS_FEATURE_VTH | CAPS_FEATURE_BUF | CAPS_FEATURE_USB30 | CAPS_FEATURE_ADF4360,
+      (1 << DSL_STREAM125x16_16) | (1 << DSL_STREAM250x12_16) | (1 << DSL_STREAM500x6) | (1 << DSL_STREAM1000x3) |
+      (1 << DSL_BUFFER500x16) | (1 << DSL_BUFFER1000x8),
+      16,
+      SR_GB(2),
+      0,
+      DSL_BUFFER500x16,
+      0,
+      samplerates1000,
+      0,
+      DSL_STREAM125x16_16,
+      SR_MHZ(1),
+      SR_Mn(1),
+      0,
+      0,
+      0,
+      0,
+      0,
+      SR_MHZ(500),
+      SR_GHZ(1)}
+    },
+
+    {0x2A0E, 0x002C, LIBUSB_SPEED_HIGH, "DreamSourceLab", "DSLogic U3Pro32", NULL,
+     "DSLogicU3Pro32.fw",
+     "DSLogicU3Pro32.bin",
+     "DSLogicU3Pro32.bin",
+     {CAPS_MODE_LOGIC,
+      CAPS_FEATURE_VTH | CAPS_FEATURE_BUF | CAPS_FEATURE_USB30  | CAPS_FEATURE_ADF4360 | CAPS_FEATURE_LA_CH32,
+      (1 << DSL_STREAM10x32_32_3DN2) | (1 << DSL_STREAM20x16_32_3DN2) | (1 << DSL_STREAM25x12_32_3DN2) | (1 << DSL_STREAM50x6_32_3DN2) | (1 << DSL_STREAM100x3_32_3DN2) |
+      (1 << DSL_BUFFER500x16) | (1 << DSL_BUFFER1000x8),
+      32,
+      SR_GB(2),
+      0,
+      DSL_BUFFER250x32,
+      0,
+      samplerates1000,
+      0,
+      DSL_STREAM10x32_32_3DN2,
+      SR_MHZ(1),
+      SR_Mn(1),
+      0,
+      0,
+      0,
+      0,
+      0,
+      SR_MHZ(500),
+      SR_GHZ(1)}
+    },
+
+    {0x2A0E, 0x002C, LIBUSB_SPEED_SUPER, "DreamSourceLab", "DSLogic U3Pro32", NULL,
+     "DSLogicU3Pro32.fw",
+     "DSLogicU3Pro32.bin",
+     "DSLogicU3Pro32.bin",
+     {CAPS_MODE_LOGIC,
+      CAPS_FEATURE_VTH | CAPS_FEATURE_BUF | CAPS_FEATURE_USB30 | CAPS_FEATURE_ADF4360 | CAPS_FEATURE_LA_CH32,
+      (1 << DSL_STREAM50x32) | (1 << DSL_STREAM100x30) | (1 << DSL_STREAM250x12) | (1 << DSL_STREAM500x6) | (1 << DSL_STREAM1000x3) |
+      (1 << DSL_BUFFER250x32) | (1 << DSL_BUFFER500x16) | (1 << DSL_BUFFER1000x8),
+      32,
+      SR_GB(2),
+      0,
+      DSL_BUFFER250x32,
+      0,
+      samplerates1000,
+      0,
+      DSL_STREAM50x32,
+      SR_MHZ(1),
+      SR_Mn(1),
+      0,
+      0,
+      0,
+      0,
+      0,
+      SR_MHZ(500),
+      SR_GHZ(1)}
+    },
+
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
 };
 
@@ -753,7 +914,7 @@ static const struct DSL_profile supported_DSCope[] = {
      "DSCopeU2B20.bin",
      "DSCopeU2B20.bin",
      {CAPS_MODE_ANALOG | CAPS_MODE_DSO,
-      CAPS_FEATURE_ZERO,
+      CAPS_FEATURE_ZERO | CAPS_FEATURE_AUTO_VGAIN,
       (1 << DSL_ANALOG10x2) |
       (1 << DSL_DSO200x2),
       2,
@@ -766,8 +927,8 @@ static const struct DSL_profile supported_DSCope[] = {
       DSL_DSO200x2,
       SR_MHZ(100),
       SR_Kn(10),
-      945,
-      1024-945,
+      930,
+      1024-930,
       10,
       245,
       22,
@@ -780,7 +941,7 @@ static const struct DSL_profile supported_DSCope[] = {
      "DSCopeU2P20.bin",
      "DSCopeU2P20.bin",
      {CAPS_MODE_ANALOG | CAPS_MODE_DSO,
-      CAPS_FEATURE_ZERO | CAPS_FEATURE_BUF | CAPS_FEATURE_POGOPIN,
+      CAPS_FEATURE_ZERO | CAPS_FEATURE_BUF | CAPS_FEATURE_POGOPIN | CAPS_FEATURE_AUTO_VGAIN,
       (1 << DSL_ANALOG10x2) |
       (1 << DSL_DSO200x2),
       2,
@@ -793,8 +954,8 @@ static const struct DSL_profile supported_DSCope[] = {
       DSL_DSO200x2,
       SR_MHZ(100),
       SR_Mn(1),
-      945,
-      1024-945,
+      930,
+      1024-930,
       10,
       245,
       22,
@@ -802,6 +963,86 @@ static const struct DSL_profile supported_DSCope[] = {
       SR_HZ(0)}
     },
 
+    {0x2A0E, 0x0028, LIBUSB_SPEED_HIGH, "DreamSourceLab", "DSCope U2B100", NULL,
+     "DSCopeU2B100.fw",
+     "DSCopeU2B100.bin",
+     "DSCopeU2B100.bin",
+     {CAPS_MODE_ANALOG | CAPS_MODE_DSO,
+      CAPS_FEATURE_ZERO | CAPS_FEATURE_HMCAD1511 | CAPS_FEATURE_20M,
+      (1 << DSL_ANALOG10x2_500) |
+      (1 << DSL_DSO1000x2),
+      2,
+      SR_KB(256),
+      SR_Kn(20),
+      0,
+      vdivs10to2000,
+      samplerates1000,
+      4,
+      DSL_DSO1000x2,
+      SR_MHZ(500),
+      SR_Kn(10),
+      850,
+      1024-850,
+      10,
+      245,
+      80,
+      SR_HZ(0),
+      SR_HZ(0)}
+    },
+
+    {0x2A0E, 0x002B, LIBUSB_SPEED_HIGH, "DreamSourceLab", "DSCope U3P100", NULL,
+     "DSCopeU3P100.fw",
+     "DSCopeU3P100.bin",
+     "DSCopeU3P100.bin",
+     {CAPS_MODE_ANALOG | CAPS_MODE_DSO,
+      CAPS_FEATURE_ZERO | CAPS_FEATURE_FLASH | CAPS_FEATURE_USB30 | CAPS_FEATURE_HMCAD1511 | CAPS_FEATURE_20M,
+      (1 << DSL_ANALOG10x2_500) |
+      (1 << DSL_DSO1000x2),
+      2,
+      SR_GB(2),
+      SR_Mn(2),
+      0,
+      vdivs10to2000,
+      samplerates1000,
+      4,
+      DSL_DSO1000x2,
+      SR_MHZ(500),
+      SR_Mn(1),
+      900,
+      1024-900,
+      10,
+      245,
+      60,
+      SR_HZ(0),
+      SR_HZ(0)}
+    },
+
+    {0x2A0E, 0x002B, LIBUSB_SPEED_SUPER, "DreamSourceLab", "DSCope U3P100", NULL,
+     "DSCopeU3P100.fw",
+     "DSCopeU3P100.bin",
+     "DSCopeU3P100.bin",
+     {CAPS_MODE_ANALOG | CAPS_MODE_DSO,
+      CAPS_FEATURE_ZERO | CAPS_FEATURE_FLASH | CAPS_FEATURE_USB30 | CAPS_FEATURE_HMCAD1511 | CAPS_FEATURE_20M,
+      (1 << DSL_ANALOG10x2_500) |
+      (1 << DSL_DSO1000x2),
+      2,
+      SR_GB(2),
+      SR_Mn(2),
+      0,
+      vdivs10to2000,
+      samplerates1000,
+      4,
+      DSL_DSO1000x2,
+      SR_MHZ(500),
+      SR_Mn(1),
+      900,
+      1024-900,
+      10,
+      245,
+      60,
+      SR_HZ(0),
+      SR_HZ(0)}
+    },
 
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
 };
@@ -880,6 +1121,9 @@ struct DSL_context {
     int16_t tune_index;
     int zero_stage;
     int zero_pcnt;
+    gboolean zero_branch;
+    gboolean zero_comb_fgain;
+    gboolean zero_comb;
     int tune_stage;
     int tune_pcnt;
     struct sr_channel *tune_probe;
@@ -908,6 +1152,7 @@ struct DSL_context {
     gboolean abort;
     gboolean overflow;
     int bw_limit;
+    int empty_poll_count;
 
     int language;
 };
@@ -1085,6 +1330,13 @@ SR_PRIV int dsl_rd_nvm(const struct sr_dev_inst *sdi, unsigned char *ctx, uint16
 SR_PRIV int dsl_rd_probe(const struct sr_dev_inst *sdi, unsigned char *ctx, uint16_t addr, uint8_t len);
 
 SR_PRIV int dsl_config_adc(const struct sr_dev_inst *sdi, const struct DSL_adc_config *config);
+SR_PRIV double dsl_adc_code2fgain(uint8_t code);
+SR_PRIV uint8_t dsl_adc_fgain2code(double gain);
+SR_PRIV int dsl_config_adc_fgain(const struct sr_dev_inst *sdi, uint8_t branch, double gain0, double gain1);
+SR_PRIV int dsl_config_fpga_fgain(const struct sr_dev_inst *sdi);
+SR_PRIV int dsl_skew_fpga_fgain(const struct sr_dev_inst *sdi, gboolean comb, double skew[]);
+SR_PRIV int dsl_probe_cali_fgain(struct DSL_context *devc, struct sr_channel *probe, double mean, gboolean comb, gboolean reset);
+SR_PRIV gboolean dsl_probe_fgain_inrange(struct sr_channel *probe, gboolean comb, double skew[]);
 
 SR_PRIV int dsl_fpga_arm(const struct sr_dev_inst *sdi);
 SR_PRIV int dsl_fpga_config(struct libusb_device_handle *hdl, const char *filename);
@@ -1101,7 +1353,7 @@ SR_PRIV int dsl_config_list(int key, GVariant **data, const struct sr_dev_inst *
 SR_PRIV int dsl_dev_open(struct sr_dev_driver *di, struct sr_dev_inst *sdi, gboolean *fpga_done);
 SR_PRIV int dsl_dev_close(struct sr_dev_inst *sdi);
 SR_PRIV int dsl_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data);
-SR_PRIV int dsl_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end);
+SR_PRIV int dsl_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg);
 
 SR_PRIV unsigned int dsl_get_timeout(const struct sr_dev_inst *sdi);
 SR_PRIV int dsl_start_transfers(const struct sr_dev_inst *sdi);
diff --git a/libsigrok4DSL/hardware/DSL/dslogic.c b/libsigrok4DSL/hardware/DSL/dslogic.c
index f174cfd989f42afb7d05d6d71f6fac5a260557dc..443c8052ff5950df409af42d7e3089dc8720a743 100755
--- a/libsigrok4DSL/hardware/DSL/dslogic.c
+++ b/libsigrok4DSL/hardware/DSL/dslogic.c
@@ -228,6 +228,9 @@ static struct DSL_context *DSLogic_dev_new(const struct DSL_profile *prof)
     devc->trigger_hrate = 0;
     devc->trigger_holdoff = 0;
     devc->zero = FALSE;
+    devc->zero_branch = FALSE;
+    devc->zero_comb_fgain = FALSE;
+    devc->zero_comb = FALSE;
     devc->status = DSL_FINISH;
 
     devc->mstatus_valid = FALSE;
@@ -932,7 +935,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
             dsl_adjust_samplerate(devc);
             if (devc->op_mode == OP_INTEST) {
                 devc->cur_samplerate = devc->stream ? channel_modes[devc->ch_mode].max_samplerate / 10 :
-                                                      channel_modes[devc->ch_mode].max_samplerate;
+                                                      SR_MHZ(100);
                 devc->limit_samples = devc->stream ? devc->cur_samplerate * 3 :
                                                      devc->profile->dev_caps.hw_depth / dsl_en_ch_num(sdi);
             }
@@ -1042,10 +1045,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
         ch->offset = g_variant_get_uint16(data);
         sr_dbg("%s: setting OFFSET of channel %d to %d", __func__,
                ch->index, ch->offset);
-    } else if (id == SR_CONF_PROBE_HW_OFFSET) {
-        ch->hw_offset = g_variant_get_uint16(data);
-        sr_dbg("%s: setting OFFSET of channel %d to %d", __func__,
-               ch->index, ch->offset);
     } else if (id == SR_CONF_TRIGGER_SOURCE) {
         devc->trigger_source = g_variant_get_byte(data);
         if (sdi->mode == DSO) {
@@ -1119,12 +1118,12 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
         for (i = 0; i < ARRAY_SIZE(channel_modes); i++) {
             if (channel_modes[i].stream == devc->stream &&
                 devc->profile->dev_caps.channels & (1 << i)) {
+                if (devc->test_mode != SR_TEST_NONE && devc->profile->dev_caps.intest_channel != channel_modes[i].id)
+                    continue;
                 if (devc->language == LANGUAGE_CN)
                     g_variant_builder_add(&gvb, "s", channel_modes[i].descr_cn);
                 else
                     g_variant_builder_add(&gvb, "s", channel_modes[i].descr);
-                if (devc->test_mode != SR_TEST_NONE)
-                    break;
             }
         }
         *data = g_variant_builder_end(&gvb);
@@ -1197,6 +1196,17 @@ static void remove_sources(struct DSL_context *devc)
     g_free(devc->usbfd);
 }
 
+static void report_overflow(struct DSL_context *devc)
+{
+    struct sr_datafeed_packet packet;
+    struct sr_dev_inst *sdi = devc->cb_data;
+
+    packet.status = SR_PKT_OK;
+    packet.type = SR_DF_OVERFLOW;
+    packet.payload = NULL;
+    sr_session_send(sdi, &packet);
+}
+
 static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi)
 {
     int completed = 0;
@@ -1218,16 +1228,44 @@ static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi)
     tv.tv_sec = tv.tv_usec = 0;
     libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, &completed);
 
-    // overflow check
-    if (devc->stream && devc->trf_completed) {
-        rd_cmd.header.dest = DSL_CTL_HW_STATUS;
-        rd_cmd.header.size = 1;
-        hw_info = 0;
-        rd_cmd.data = &hw_info;
+    if (devc->trf_completed)
+        devc->empty_poll_count = 0;
+    else
+        devc->empty_poll_count++;
+
+    // --
+    // progress check
+    // must before overflow check (1ch@10K)
+    // --
+    if ((devc->empty_poll_count > MAX_EMPTY_POLL) && (devc->status == DSL_START)) {
+        devc->mstatus.captured_cnt0 = 0;
+        rd_cmd.header.dest = DSL_CTL_I2C_STATUS;
+        rd_cmd.header.offset = 0;
+        rd_cmd.header.size = 4;
+        rd_cmd.data = (unsigned char*)&devc->mstatus;
         if ((ret = command_ctl_rd(usb->devhdl, rd_cmd)) != SR_OK)
-            sr_err("Failed to get hardware infos.");
-        else
-            devc->overflow = (hw_info & bmSYS_OVERFLOW) != 0;
+            sr_err("Failed to get progress infos.");
+
+        devc->empty_poll_count = 0;
+    }
+
+    // overflow check
+    if (devc->stream) {
+        if (devc->empty_poll_count > MAX_EMPTY_POLL) {
+            rd_cmd.header.dest = DSL_CTL_HW_STATUS;
+            rd_cmd.header.size = 1;
+            hw_info = 0;
+            rd_cmd.data = &hw_info;
+            if ((ret = command_ctl_rd(usb->devhdl, rd_cmd)) != SR_OK)
+                sr_err("Failed to get hardware infos.");
+            else
+                devc->overflow = (hw_info & bmSYS_OVERFLOW) != 0;
+
+            if (devc->overflow)
+                report_overflow(devc);
+
+            devc->empty_poll_count = 0;
+        }
     }
 
     if (devc->status == DSL_FINISH) {
@@ -1263,13 +1301,19 @@ static int dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data)
     devc->num_samples = 0;
     devc->num_bytes = 0;
     devc->empty_transfer_count = 0;
+    devc->empty_poll_count = 0;
     devc->status = DSL_INIT;
     devc->num_transfers = 0;
     devc->submitted_transfers = 0;
-    devc->actual_samples = (devc->limit_samples + 1023ULL) & ~1023ULL;
+    devc->actual_samples = (devc->limit_samples + SAMPLES_ALIGN) & ~SAMPLES_ALIGN;
     devc->actual_bytes = devc->actual_samples / DSLOGIC_ATOMIC_SAMPLES * dsl_en_ch_num(sdi) * DSLOGIC_ATOMIC_SIZE;
 	devc->abort = FALSE;
     devc->mstatus_valid = FALSE;
+    devc->mstatus.captured_cnt0 = 0;
+    devc->mstatus.captured_cnt1 = 0;
+    devc->mstatus.captured_cnt2 = 0;
+    devc->mstatus.captured_cnt3 = 0;
+    devc->mstatus.trig_hit = 0;
     devc->overflow = FALSE;
 
 	/* Configures devc->trigger_* and devc->sample_wide */
@@ -1346,9 +1390,9 @@ static int dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data)
     return ret;
 }
 
-static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end)
+static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg)
 {
-    int ret = dsl_dev_status_get(sdi, status, prg, begin, end);
+    int ret = dsl_dev_status_get(sdi, status, prg);
     return ret;
 }
 
diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c
index ce1550db5833254597a553d75469b230adcc555a..5539d5fb64126c2cc5a68b317d8d3fafe18b5802 100755
--- a/libsigrok4DSL/hardware/demo/demo.c
+++ b/libsigrok4DSL/hardware/demo/demo.c
@@ -1074,11 +1074,10 @@ static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data)
 	return SR_OK;
 }
 
-static int hw_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end)
+static int hw_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg)
 {
     (void)prg;
-    (void)begin;
-    (void)end;
+
     if (sdi) {
         struct demo_context *const devc = sdi->priv;
         *status = devc->mstatus;
diff --git a/libsigrok4DSL/hwdriver.c b/libsigrok4DSL/hwdriver.c
index 2d921dc1e32a2c7a9990d5893f2913367672a631..6af67d91c443f47ea5ce80004e9967d950507e3f 100755
--- a/libsigrok4DSL/hwdriver.c
+++ b/libsigrok4DSL/hwdriver.c
@@ -425,8 +425,7 @@ SR_API const struct sr_config_info *sr_config_info_get(int key)
  *         as an indication that it's not applicable.
  */
 SR_API int sr_status_get(const struct sr_dev_inst *sdi,
-                         struct sr_status *status,
-                         gboolean prg, int begin, int end)
+                         struct sr_status *status, gboolean prg)
 {
     int ret;
 
@@ -435,7 +434,7 @@ SR_API int sr_status_get(const struct sr_dev_inst *sdi,
     else if (!sdi->driver->dev_status_get)
         ret = SR_ERR_ARG;
     else
-        ret = sdi->driver->dev_status_get(sdi, status, prg, begin, end);
+        ret = sdi->driver->dev_status_get(sdi, status, prg);
 
     return ret;
 }
diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h
index b6e181011b743df22dc3f06f0d01b6568aaaa862..77d01ebe41151c578a5c3800b97240fd6b8b6c3f 100755
--- a/libsigrok4DSL/libsigrok.h
+++ b/libsigrok4DSL/libsigrok.h
@@ -126,6 +126,8 @@ enum {
 #define DS_CONF_DSO_VDIVS 10
 
 #define DS_MAX_TRIG_PERCENT 90
+
+#define SAMPLES_ALIGN 1023ULL
 /*
  * Oscilloscope
  */
@@ -647,6 +649,16 @@ struct sr_channel {
     int8_t comb_diff_top;
     int8_t comb_diff_bom;
     int8_t comb_comp;
+    uint16_t digi_fgain;
+
+    double cali_fgain0;
+    double cali_fgain1;
+    double cali_fgain2;
+    double cali_fgain3;
+    double cali_comb_fgain0;
+    double cali_comb_fgain1;
+    double cali_comb_fgain2;
+    double cali_comb_fgain3;
 
     gboolean map_default;
     const char *map_unit;
@@ -680,17 +692,6 @@ struct sr_config_info {
 	char *description;
 };
 
-enum {
-    SR_STATUS_TRIG_BEGIN = 0,
-    SR_STATUS_TRIG_END = 4,
-    SR_STATUS_CH0_BEGIN = 5,
-    SR_STATUS_CH0_END = 14,
-    SR_STATUS_CH1_BEGIN = 15,
-    SR_STATUS_CH1_END = 24,
-    SR_STATUS_ZERO_BEGIN = 128,
-    SR_STATUS_ZERO_END = 135,
-};
-
 struct sr_status {
     uint8_t trig_hit;
     uint8_t captured_cnt3;
@@ -722,6 +723,9 @@ struct sr_status {
     uint32_t ch0_cyc_flen;
     uint64_t ch0_acc_square;
     uint32_t ch0_acc_mean;
+    uint32_t ch0_acc_mean_p1;
+    uint32_t ch0_acc_mean_p2;
+    uint32_t ch0_acc_mean_p3;
 
     uint8_t ch1_max;
     uint8_t ch1_min;
@@ -737,6 +741,9 @@ struct sr_status {
     uint32_t ch1_cyc_flen;
     uint64_t ch1_acc_square;
     uint32_t ch1_acc_mean;
+    uint32_t ch1_acc_mean_p1;
+    uint32_t ch1_acc_mean_p2;
+    uint32_t ch1_acc_mean_p3;
 };
 
 enum {
@@ -877,6 +884,8 @@ enum {
     SR_CONF_ZERO_SET,
     SR_CONF_ZERO_LOAD,
     SR_CONF_ZERO_DEFAULT,
+    SR_CONF_ZERO_COMB_FGAIN,
+    SR_CONF_ZERO_COMB,
     SR_CONF_VOCM,
     SR_CONF_CALI,
 
@@ -1199,8 +1208,7 @@ struct sr_dev_driver {
 	int (*dev_open) (struct sr_dev_inst *sdi);
 	int (*dev_close) (struct sr_dev_inst *sdi);
     int (*dev_status_get) (const struct sr_dev_inst *sdi,
-                           struct sr_status *status,
-                           gboolean prg, int begin, int end);
+                           struct sr_status *status, gboolean prg);
     int (*dev_acquisition_start) (struct sr_dev_inst *sdi,
 			void *cb_data);
     int (*dev_acquisition_stop) (const struct sr_dev_inst *sdi,
diff --git a/libsigrok4DSL/proto.h b/libsigrok4DSL/proto.h
index 84ffaae20ea56a110e3e99dab2b7e4fc00d327c7..aeac6b8108c4a31e212c63365bca24b86bba3e4c 100755
--- a/libsigrok4DSL/proto.h
+++ b/libsigrok4DSL/proto.h
@@ -78,7 +78,7 @@ SR_API int sr_config_list(const struct sr_dev_driver *driver,
                           int key, GVariant **data);
 SR_API const struct sr_config_info *sr_config_info_get(int key);
 SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname);
-SR_API int sr_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end);
+SR_API int sr_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg);
 SR_API struct sr_config *sr_config_new(int key, GVariant *data);
 SR_API void sr_config_free(struct sr_config *src);
 
diff --git a/libsigrok4DSL/session_driver.c b/libsigrok4DSL/session_driver.c
index ce4281e58f92223bdbbf146c65e6b49979314f6c..aca809bee6be670595f5964fe91aa49750649d02 100755
--- a/libsigrok4DSL/session_driver.c
+++ b/libsigrok4DSL/session_driver.c
@@ -867,11 +867,9 @@ static int config_list(int key, GVariant **data,
 	return SR_OK;
 }
 
-static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end)
+static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg)
 {
     (void)prg;
-    (void)begin;
-    (void)end;
 
     struct session_vdev *vdev;