limitation imposed by ``serial8250_get_baud_rate`` standard baud rates
below 300bps become unavailable in the regular way, e.g. the rate of
200bps requires the baud base to be divided by 78125 and that is beyond
-the unsigned 16-bit range. The historic spd_cust feature can still be
-used by encoding the values for, the prescaler, the oversampling rate
-and the clock divisor (DLM/DLL) as follows to obtain such rates if so
-required:
-
-::
-
- 31 29 28 20 19 16 15 0
- +-----+-----------------+-------+-------------------------------+
- |0 0 0| CPR2:CPR | TCR | DLM:DLL |
- +-----+-----------------+-------+-------------------------------+
-
-Use a value such encoded for the ``custom_divisor`` field along with the
-ASYNC_SPD_CUST flag set in the ``flags`` field in ``struct serial_struct``
-passed with the TIOCSSERIAL ioctl(2), such as with the setserial(8)
-utility and its ``divisor`` and ``spd_cust`` parameters, and then select
-the baud rate of 38400bps. Note that the value of 0 in TCR sets the
-oversampling rate to 16 and prescaler values below 1 in CPR2/CPR are
-clamped by the driver to 1.
-
-For example the value of 0x1f4004e2 will set CPR2/CPR, TCR and DLM/DLL
-respectively to 0x1f4, 0x0 and 0x04e2, choosing the prescaler value,
-the oversampling rate and the clock divisor of 62.500, 16 and 1250
-respectively. These parameters will set the baud rate for the serial
-port to 62500000 / 62.500 / 1250 / 16 = 50bps.
+the unsigned 16-bit range.
Maciej W. Rozycki <macro@orcam.me.uk>
u8 tcr;
int i;
- /* Old custom speed handling. */
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
- unsigned int cust_div = port->custom_divisor;
-
- quot = cust_div & UART_DIV_MAX;
- tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK;
- cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK;
- if (cpr < OXSEMI_TORNADO_CPR_MIN)
- cpr = OXSEMI_TORNADO_CPR_DEF;
- } else {
- best_squot = quot_scale;
- for (i = 0; i < ARRAY_SIZE(p); i++) {
- unsigned int spre;
- unsigned int srem;
- u8 cp;
- u8 tc;
-
- tc = p[i][0];
- cp = p[i][1];
- spre = tc * cp;
-
- srem = sdiv % spre;
- if (srem > spre / 2)
- srem = spre - srem;
- squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
-
- if (srem == 0) {
- tcr = tc;
- cpr = cp;
- quot = sdiv / spre;
- break;
- } else if (squot < best_squot) {
- best_squot = squot;
- tcr = tc;
- cpr = cp;
- quot = DIV_ROUND_CLOSEST(sdiv, spre);
- }
+ best_squot = quot_scale;
+ for (i = 0; i < ARRAY_SIZE(p); i++) {
+ unsigned int spre;
+ unsigned int srem;
+ u8 cp;
+ u8 tc;
+
+ tc = p[i][0];
+ cp = p[i][1];
+ spre = tc * cp;
+
+ srem = sdiv % spre;
+ if (srem > spre / 2)
+ srem = spre - srem;
+ squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
+
+ if (srem == 0) {
+ tcr = tc;
+ cpr = cp;
+ quot = sdiv / spre;
+ break;
+ } else if (squot < best_squot) {
+ best_squot = squot;
+ tcr = tc;
+ cpr = cp;
+ quot = DIV_ROUND_CLOSEST(sdiv, spre);
}
- while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
- quot % 2 == 0) {
+ }
+ while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
+ quot % 2 == 0) {
+ quot >>= 1;
+ tcr <<= 1;
+ }
+ while (quot > UART_DIV_MAX) {
+ if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
quot >>= 1;
tcr <<= 1;
- }
- while (quot > UART_DIV_MAX) {
- if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
- quot >>= 1;
- tcr <<= 1;
- } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
- quot >>= 1;
- cpr <<= 1;
- } else {
- quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
- cpr = OXSEMI_TORNADO_CPR_MASK;
- }
+ } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
+ quot >>= 1;
+ cpr <<= 1;
+ } else {
+ quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
+ cpr = OXSEMI_TORNADO_CPR_MASK;
}
}