These changes are a raw update to a vanilla kernel 4.1.10, with the
[kvmfornfv.git] / kernel / drivers / usb / serial / pl2303.c
index f5257af..ae682e4 100644 (file)
@@ -362,21 +362,38 @@ static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4],
 static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
                                                                speed_t baud)
 {
-       unsigned int tmp;
+       unsigned int baseline, mantissa, exponent;
 
        /*
         * Apparently the formula is:
-        * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
+        *   baudrate = 12M * 32 / (mantissa * 4^exponent)
+        * where
+        *   mantissa = buf[8:0]
+        *   exponent = buf[11:9]
         */
-       tmp = 12000000 * 32 / baud;
+       baseline = 12000000 * 32;
+       mantissa = baseline / baud;
+       if (mantissa == 0)
+               mantissa = 1;   /* Avoid dividing by zero if baud > 32*12M. */
+       exponent = 0;
+       while (mantissa >= 512) {
+               if (exponent < 7) {
+                       mantissa >>= 2; /* divide by 4 */
+                       exponent++;
+               } else {
+                       /* Exponent is maxed. Trim mantissa and leave. */
+                       mantissa = 511;
+                       break;
+               }
+       }
+
        buf[3] = 0x80;
        buf[2] = 0;
-       buf[1] = (tmp >= 256);
-       while (tmp >= 256) {
-               tmp >>= 2;
-               buf[1] <<= 1;
-       }
-       buf[0] = tmp;
+       buf[1] = exponent << 1 | mantissa >> 8;
+       buf[0] = mantissa & 0xff;
+
+       /* Calculate and return the exact baud rate. */
+       baud = (baseline / mantissa) >> (exponent << 1);
 
        return baud;
 }