Hello Greg,

mcfserial tweaks [1/3] - Implement mcfrs_wait_until_sent()
(ported forward from 2.4.20-uc0)

Patch submitted by Bernardo Innocenti <bernie@develer.com>
Applies to 2.5.75-uc0 (and most probably 2.6.0-test1).


diff -Nru linux-2.5.75-uc0/drivers/serial/mcfserial.c linux-2.5.75-uc0-develer/drivers/serial/mcfserial.c
--- linux-2.5.75-uc0/drivers/serial/mcfserial.c	2003-07-12 20:25:18.000000000 +0200
+++ linux-2.5.75-uc0-develer/drivers/serial/mcfserial.c	2003-07-15 20:22:28.000000000 +0200
@@ -143,6 +143,7 @@
  *	Forware declarations...
  */
 static void	mcfrs_change_speed(struct mcf_serial *info);
+static void	mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
 
 
 static inline int serial_paranoia_check(struct mcf_serial *info,
@@ -1246,6 +1266,76 @@
 }
 
 /*
+ * mcfrs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void
+mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+#ifdef	CONFIG_M5272
+#define	MCF5272_FIFO_SIZE	25		/* fifo size + shift reg */
+
+	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
+	volatile unsigned char *uartp;
+	unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
+	
+	if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
+		return;
+	
+	orig_jiffies = jiffies;
+
+	/*
+	 * Set the check interval to be 1/5 of the approximate time
+	 * to send the entire fifo, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 *
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
+	char_time = fifo_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout && timeout < char_time)
+		char_time = timeout;
+
+	/*
+	 * Clamp the timeout period at 2 * the time to empty the
+	 * fifo.  Just to be safe, set the minimum at .5 seconds.
+	 */
+	fifo_time *= 2;
+	if (fifo_time < (HZ/2))
+		fifo_time = HZ/2;
+	if (!timeout || timeout > fifo_time)
+		timeout = fifo_time;
+
+	/*
+	 * Account for the number of bytes in the UART
+	 * transmitter FIFO plus any byte being shifted out.
+	 */
+	uartp = (volatile unsigned char *) info->addr;
+	for (;;) {
+		fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
+		if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
+				MCFUART_USR_TXEMPTY)) ==
+			MCFUART_USR_TXREADY)
+			fifo_cnt++;
+		if (fifo_cnt == 0)
+			break;
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+	}
+#else
+	/*
+	 * For the other coldfire models, assume all data has been sent
+	 */
+#endif
+}
+
+/*
  * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
  */
 void mcfrs_hangup(struct tty_struct *tty)
@@ -1570,6 +1660,7 @@
 	.start = mcfrs_start,
 	.hangup = mcfrs_hangup,
 	.read_proc = mcfrs_readproc,
+	.wait_until_sent = mcfrs_wait_until_sent,
 };
 
 /* mcfrs_init inits the driver */
