Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Calculate uchcom(4) dividers differently; usuall...



details:   https://anonhg.NetBSD.org/src/rev/a69e17a9b326
branches:  trunk
changeset: 446635:a69e17a9b326
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Thu Dec 13 01:40:02 2018 +0000

description:
Calculate uchcom(4) dividers differently; usually the same, but sometimes better.

diffstat:

 sys/dev/usb/uchcom.c |  83 ++++++++++++++++++++++++---------------------------
 1 files changed, 39 insertions(+), 44 deletions(-)

diffs (124 lines):

diff -r 356f03a457ab -r a69e17a9b326 sys/dev/usb/uchcom.c
--- a/sys/dev/usb/uchcom.c      Thu Dec 13 01:29:10 2018 +0000
+++ b/sys/dev/usb/uchcom.c      Thu Dec 13 01:40:02 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uchcom.c,v 1.26 2018/12/13 00:36:30 jakllsch Exp $     */
+/*     $NetBSD: uchcom.c,v 1.27 2018/12/13 01:40:02 jakllsch Exp $     */
 
 /*
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uchcom.c,v 1.26 2018/12/13 00:36:30 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uchcom.c,v 1.27 2018/12/13 01:40:02 jakllsch Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -91,8 +91,6 @@
 #define UCHCOM_VER_20          0x20
 #define UCHCOM_VER_30          0x30
 
-#define UCHCOM_BASE_UNKNOWN    0
-
 #define UCHCOM_BPS_PRE_IMM     0x80    /* CH341: immediate RX forwarding */
 
 #define UCHCOM_DTR_MASK                0x20
@@ -154,25 +152,14 @@
        uint8_t         dv_div;
 };
 
-struct uchcom_divider_record
-{
-       uint32_t                dvr_high;
-       uint32_t                dvr_low;
-       uint32_t                dvr_base_clock;
-       struct uchcom_divider   dvr_divider;
+static const uint32_t rates4x[8] = {
+       [0] = 4 * 12000000 / 1024,
+       [1] = 4 * 12000000 / 128,
+       [2] = 4 * 12000000 / 16,
+       [3] = 4 * 12000000 / 2,
+       [7] = 4 * 12000000,
 };
 
-static const struct uchcom_divider_record dividers[] =
-{
-       {  307200, 307200, UCHCOM_BASE_UNKNOWN, { 7, 0xD9 } },
-       {  921600, 921600, UCHCOM_BASE_UNKNOWN, { 7, 0xF3 } },
-       { 2999999,  23530,             6000000, { 3,    0 } },
-       {   23529,   2942,              750000, { 2,    0 } },
-       {    2941,    368,               93750, { 1,    0 } },
-       {     367,      1,               11719, { 0,    0 } },
-};
-#define NUM_DIVIDERS   (sizeof (dividers) / sizeof (dividers[0]))
-
 static const struct usb_devno uchcom_devs[] = {
        { USB_VENDOR_QINHENG2, USB_PRODUCT_QINHENG2_CH341SER },
        { USB_VENDOR_QINHENG, USB_PRODUCT_QINHENG_CH340 },
@@ -646,33 +633,41 @@
 static int
 calc_divider_settings(struct uchcom_divider *dp, uint32_t rate)
 {
-       int i;
-       const struct uchcom_divider_record *rp;
-       uint32_t div, rem;
+       size_t i;
+       uint32_t best, div, pre;
+       const uint32_t rate4x = rate * 4U;
+
+       if (rate == 0 || rate > 3000000)
+               return -1;
+
+       pre = __arraycount(rates4x);
+       best = UINT32_MAX;
 
-       /* find record */
-       for (i=0; i<NUM_DIVIDERS; i++) {
-               if (dividers[i].dvr_high >= rate &&
-                   dividers[i].dvr_low <= rate) {
-                       rp = &dividers[i];
-                       goto found;
+       for (i = 0; i < __arraycount(rates4x); i++) {
+               uint32_t score, try;
+               try = rates4x[i] * 2 / rate4x;
+               try = (try / 2) + (try & 1);
+               if (try < 2)
+                       continue;
+               if (try > 255)
+                       try = 255;
+               score = abs((int)rate4x - rates4x[i] / try);
+               if (score < best) {
+                       best = score;
+                       pre = i;
+                       div = try;
                }
        }
-       return -1;
 
-found:
-       dp->dv_prescaler = rp->dvr_divider.dv_prescaler;
-       if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN)
-               dp->dv_div = rp->dvr_divider.dv_div;
-       else {
-               div = rp->dvr_base_clock / rate;
-               rem = rp->dvr_base_clock % rate;
-               if (div==0 || div>=0xFF)
-                       return -1;
-               if ((rem<<1) >= rate)
-                       div += 1;
-               dp->dv_div = (uint8_t)-div;
-       }
+       if (pre >= __arraycount(rates4x))
+               return -1;
+       if ((rates4x[pre] / div / 4) < (rate * 99 / 100))
+               return -1;
+       if ((rates4x[pre] / div / 4) > (rate * 101 / 100))
+               return -1;
+
+       dp->dv_prescaler = pre;
+       dp->dv_div = (uint8_t)-div;
 
        return 0;
 }



Home | Main Index | Thread Index | Old Index