Re: non-standard baud rates with Prolific 2303 USB-serial

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

 



So on more investigation and many hours of trial and error I have determined the correct formua for the non-standard rates with this Prolific 2303.
There are four bytes used to send the baud rate. When not using the 'standard' rates, the Linus driver sets byte 3 to 0x80 and bytes 1 and 0 hold the divisor of the clock (12MHz * 32).
This divisor is encoded in a special way. The 'exponent' (log 4) and the mantissa. This is calculated by dividing the divisor by 4 until it is less than 512 (the number of times you can
do this is the exponent). e then goes in bits 1,2 and 3 of byte 1 with the MSBit of the mantissa in bit 0 of byte 1. Byte 0 holds the lower 8 bits of the mantissa.

This does not work on the device I have USB PID/VID/REV is 0673 / 2303/3.00. Instead...the calculation uses 1024 instead of 512 in the method above and the exponent is in byte 1 bits 7,6&5 (the top 2 bits of the mantissa are in bits 0 and 1).
I tested this on all baud rates that stty will allow that are not 'standard' and it works. (50, 110 .... 3000000).

The changed routine is below. I presume the original driver worked so perhaps this device is a new variant with the same USB VID/PID.

Michael

static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
                                speed_t baud)
{
    unsigned int baseline, mantissa, exponent;
    /*
     * Apparently the formula is:
     *   baudrate = 12M * 32 / (mantissa * 4^exponent)
     * where
     *   mantissa = buf[8:0]
     *   exponent = buf[11:9]
         *
         * Michael Katzmann: At least versions of the chip VID 0x067b PID 0x2303 bcdDevice 3.00
         *                   uses mantissa = buf[9:0]
     *                        exponent = buf[15:13]
     */
    baseline = 12000000 * 32;
    mantissa = baseline / baud;
    if (mantissa == 0)
        mantissa = 1;    /* Avoid dividing by zero if baud > 32*12M. */
    exponent = 0;
#undef ORIGINAL
#ifdef ORIGINAL
    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] = exponent << 1 | mantissa >> 8;
    buf[0] = mantissa & 0xff;
#else
    while (mantissa >= 1024) {
        if (exponent < 7) {
            mantissa >>= 2;    /* divide by 4 */
            exponent++;
        } else {
            // This is an logical modification of the original code
                        // but I do not know if this an actual limitation
            /* Exponent is maxed. Trim mantissa and leave. */
            mantissa = 1023 ;
            break;
        }
    }
    buf[3] = 0x80;
    buf[2] = 0;
    buf[1] = exponent << 5 | (mantissa >> 8);
    buf[0] = mantissa & 0xff;
#endif
    /* Calculate and return the exact baud rate. */
    baud = (baseline / mantissa) >> (exponent << 1);

    return baud;
}


On 2/21/21 10:37 AM, Michael G. Katzmann wrote:
> The Linux driver does not seem to produce sensible baud rated for other than the 'supported' rates.
>
> stty to 110 bd results in ~95,000 bd (that's not a typo but 95 thousand). Other rates like 200 also produce odd speeds although not in a logical manner.
>
> The data sheets don't describe the formula used for deriving the four bytes used to set the speed.
>
> I tried adding 110 to the supported rates but this did not produce the correct baud rate so I presume the Windows driver is using a formula different than the one in the Linux driver for 'non standard' baud rates.
>




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux