--- linux-2.6.21.1.orig/drivers/serial/atmel_serial.c	2007-05-28 12:22:29.000000000 +0200
+++ linux-2.6.21.1/drivers/serial/atmel_serial.c	2007-05-28 16:39:09.000000000 +0200
@@ -174,7 +174,35 @@
 				at91_set_gpio_value(AT91_PIN_PA21, 0);
 			else
 				at91_set_gpio_value(AT91_PIN_PA21, 1);
+
+      /*
+       * FDL VersaLink adds GPIOS to provide full modem control on
+       * USART 0 - Drive DTR and RI pins manually
+       */
+      if (mctrl & TIOCM_DTR)
+        at91_set_gpio_value(AT91_PIN_PB6, 0);
+      else
+        at91_set_gpio_value(AT91_PIN_PB6, 1);
+      if (mctrl & TIOCM_RI)
+        at91_set_gpio_value(AT91_PIN_PB7, 0);
+      else
+        at91_set_gpio_value(AT91_PIN_PB7, 1);
 		}
+
+    /*
+     * FDL VersaLink adds GPIOS to provide full modem control on
+     * USART 3 - Drive DTR and RI pins manually
+     */
+    if (port->mapbase == AT91RM9200_BASE_US3) {
+      if (mctrl & TIOCM_DTR)
+        at91_set_gpio_value(AT91_PIN_PB29, 0);
+      else
+        at91_set_gpio_value(AT91_PIN_PB29, 1);
+      if (mctrl & TIOCM_RI)
+        at91_set_gpio_value(AT91_PIN_PB2, 0);
+      else
+        at91_set_gpio_value(AT91_PIN_PB2, 1);
+    }
 	}
 #endif
 
@@ -211,8 +239,10 @@
 	/*
 	 * The control signals are active low.
 	 */
-	if (!(status & ATMEL_US_DCD))
-		ret |= TIOCM_CD;
+
+  if (!(port->mapbase == AT91RM9200_BASE_US0 || port->mapbase == AT91RM9200_BASE_US3))
+		if (!(status & ATMEL_US_DCD))
+			ret |= TIOCM_CD;
 	if (!(status & ATMEL_US_CTS))
 		ret |= TIOCM_CTS;
 	if (!(status & ATMEL_US_DSR))
@@ -220,6 +250,16 @@
 	if (!(status & ATMEL_US_RI))
 		ret |= TIOCM_RI;
 
+  /*
+   * Read the GPIO's for the FDL VersaLink special case
+   */
+  if (port->mapbase == AT91RM9200_BASE_US0)
+    if (!(at91_get_gpio_value(AT91_PIN_PA19)))
+      ret |= TIOCM_CD;
+  if (port->mapbase == AT91RM9200_BASE_US3)
+    if (!(at91_get_gpio_value(AT91_PIN_PA24)))
+      ret |= TIOCM_CD;
+
 	return ret;
 }
 
@@ -511,6 +551,34 @@
 }
 
 /*
+ * USART0 DCD Interrupt handler
+ */
+
+static irqreturn_t atmel_u0_DCD_interrupt(int irq, void *dev_id)
+{
+  struct uart_port *port = dev_id;
+  int status = at91_get_gpio_value(irq);
+
+  uart_handle_dcd_change(port, !(status));
+
+  return IRQ_HANDLED;
+}
+
+/*
+ * USART3 DCD Interrupt handler
+ */
+
+static irqreturn_t atmel_u3_DCD_interrupt(int irq, void *dev_id)
+{
+  struct uart_port *port = dev_id;
+  int status = at91_get_gpio_value(irq);
+
+  uart_handle_dcd_change(port, !(status));
+
+  return IRQ_HANDLED;
+}
+
+/*
  * Interrupt handler
  */
 static irqreturn_t atmel_interrupt(int irq, void *dev_id)
@@ -587,6 +655,23 @@
 		return retval;
 	}
 
+	if (port->mapbase == AT91RM9200_BASE_US0) {
+		retval = request_irq(AT91_PIN_PA19, atmel_u0_DCD_interrupt, 0, "atmel_serial", port);
+		if (retval) {
+			printk("atmel_serial: atmel_startup - Can't get u0DCD irq\n");
+			free_irq(port->irq, port);
+			return retval;
+		}
+	}
+	if (port->mapbase == AT91RM9200_BASE_US3) {
+		retval = request_irq(AT91_PIN_PA24, atmel_u3_DCD_interrupt, 0, "atmel_serial", port);
+		if (retval) {
+			printk("atmel_serial: atmel_startup - Can't get u3DCD irq\n");
+			free_irq(port->irq, port);
+			return retval;
+		}
+	}
+
 	/*
 	 * Initialize DMA (if necessary)
 	 */
@@ -603,6 +688,10 @@
 					kfree(atmel_port->pdc_rx[0].buf);
 				}
 				free_irq(port->irq, port);
+        if (port->mapbase == AT91RM9200_BASE_US0)
+          free_irq(AT91_PIN_PA19, port);
+        if (port->mapbase == AT91RM9200_BASE_US3)
+          free_irq(AT91_PIN_PA24, port);
 				return -ENOMEM;
 			}
 			pdc->dma_addr = dma_map_single(port->dev, pdc->buf, PDC_BUFFER_SIZE, DMA_FROM_DEVICE);
@@ -636,6 +725,10 @@
 		retval = atmel_open_hook(port);
 		if (retval) {
 			free_irq(port->irq, port);
+      if (port->mapbase == AT91RM9200_BASE_US0)
+        free_irq(AT91_PIN_PA19, port);
+      if (port->mapbase == AT91RM9200_BASE_US3)
+        free_irq(AT91_PIN_PA24, port);
 			return retval;
 		}
 	}
@@ -701,6 +794,10 @@
 	 * Free the interrupt
 	 */
 	free_irq(port->irq, port);
+  if (port->mapbase == AT91RM9200_BASE_US0)
+    free_irq(AT91_PIN_PA19, port);
+  if (port->mapbase == AT91RM9200_BASE_US3)
+    free_irq(AT91_PIN_PA24, port);
 
 	/*
 	 * If there is a specific "close" function (to unregister