EXPORT_SYMBOL(tty_termios_input_baud_rate);
 
-#ifdef BOTHER
-
 /**
  *     tty_termios_encode_baud_rate
  *     @termios: ktermios structure holding user requested state
  *
  *     Locking: Caller should hold termios lock. This is already held
  *     when calling this function from the driver termios handler.
+ *
+ *     The ifdefs deal with platforms whose owners have yet to update them
+ *     and will all go away once this is done.
  */
 
 void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
        int iclose = ibaud/50, oclose = obaud/50;
        int ibinput = 0;
 
+       if (obaud == 0)                 /* CD dropped             */
+               ibaud = 0;              /* Clear ibaud to be sure */
+
        termios->c_ispeed = ibaud;
        termios->c_ospeed = obaud;
 
+#ifdef BOTHER
        /* If the user asked for a precise weird speed give a precise weird
           answer. If they asked for a Bfoo speed they many have problems
           digesting non-exact replies so fuzz a bit */
                iclose = 0;
        if ((termios->c_cflag >> IBSHIFT) & CBAUD)
                ibinput = 1;    /* An input speed was specified */
-
+#endif
        termios->c_cflag &= ~CBAUD;
 
+       /*
+        *      Our goal is to find a close match to the standard baud rate
+        *      returned. Walk the baud rate table and if we get a very close
+        *      match then report back the speed as a POSIX Bxxxx value by
+        *      preference
+        */
+
        do {
                if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
                        termios->c_cflag |= baud_bits[i];
                        ofound = i;
                }
                if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
-                       /* For the case input == output don't set IBAUD bits if the user didn't do so */
-                       if (ofound != i || ibinput)
+                       if (ofound == i && !ibinput)
+                               ifound  = i;
+#ifdef IBSHIFT
+                       else {
+                               ifound = i;
                                termios->c_cflag |= (baud_bits[i] << IBSHIFT);
-                       ifound = i;
+                       }
+#endif
                }
        } while (++i < n_baud_table);
+
+       /*
+        *      If we found no match then use BOTHER if provided or warn
+        *      the user their platform maintainer needs to wake up if not.
+        */
+#ifdef BOTHER
        if (ofound == -1)
                termios->c_cflag |= BOTHER;
        /* Set exact input bits only if the input and output differ or the
           user already did */
        if (ifound == -1 && (ibaud != obaud || ibinput))
                termios->c_cflag |= (BOTHER << IBSHIFT);
+#else
+       if (ifound == -1 || ofound == -1) {
+               static int warned;
+               if (!warned++)
+                       printk(KERN_WARNING "tty: Unable to return correct "
+                         "speed data as your architecture needs updating.\n");
+       }
+#endif
 }
-
 EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
 
-#endif
+void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
+{
+       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+}
+EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
 
 /**
  *     tty_get_baud_rate       -       get tty bit rates
 
 EXPORT_SYMBOL(tty_get_baud_rate);
 
+/**
+ *     tty_termios_copy_hw     -       copy hardware settings
+ *     @new: New termios
+ *     @old: Old termios
+ *
+ *     Propogate the hardware specific terminal setting bits from
+ *     the old termios structure to the new one. This is used in cases
+ *     where the hardware does not support reconfiguration or as a helper
+ *     in some cases where only minimal reconfiguration is supported
+ */
+
+void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
+{
+       /* The bits a dumb device handles in software. Smart devices need
+          to always provide a set_termios method */
+       new->c_cflag &= HUPCL | CREAD | CLOCAL;
+       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
+       new->c_ispeed = old->c_ispeed;
+       new->c_ospeed = old->c_ospeed;
+}
+
+EXPORT_SYMBOL(tty_termios_copy_hw);
+
 /**
  *     change_termios          -       update termios values
  *     @tty: tty to update
                tty->erasing = 0;
        }
        
-       
+       /* This bit should be in the ldisc code */
        if (canon_change && !L_ICANON(tty) && tty->read_cnt)
                /* Get characters left over from canonical mode. */
                wake_up_interruptible(&tty->read_wait);
 
        /* See if packet mode change of state. */
-
        if (tty->link && tty->link->packet) {
                int old_flow = ((old_termios.c_iflag & IXON) &&
                                (old_termios.c_cc[VSTOP] == '\023') &&
           
        if (tty->driver->set_termios)
                (*tty->driver->set_termios)(tty, &old_termios);
+       else
+               tty_termios_copy_hw(tty->termios, &old_termios);
 
        ld = tty_ldisc_ref(tty);
        if (ld != NULL) {
        }
 
        change_termios(tty, &tmp_termios);
+
+       /* FIXME: Arguably if tmp_termios == tty->termios AND the
+          actual requested termios was not tmp_termios then we may
+          want to return an error as no user requested change has
+          succeeded */
        return 0;
 }