Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision c7235d406c9f48bc7726e08e21dba76c83e04a5d)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 56fd7cf53b8ee7af3e78e2237e566926562e0291)
@@ -58,7 +58,5 @@
 #include <ops/char_dev.h>
 
-#include <devman.h>
 #include <ns.h>
-#include <ipc/devman.h>
 #include <ipc/services.h>
 #include <ipc/irc.h>
@@ -82,4 +80,6 @@
 /** Interrupt ID Register definition. */
 #define	NS8250_IID_ACTIVE	(1 << 0)
+#define NS8250_IID_CAUSE_MASK 0x0e
+#define NS8250_IID_CAUSE_RXSTATUS 0x06
 
 /** FIFO Control Register definition. */
@@ -125,10 +125,4 @@
 #define	NS8250_MSR_SIGNALS	(NS8250_MSR_CTS | NS8250_MSR_DSR \
     | NS8250_MSR_RI | NS8250_MSR_DCD)
-
-/** Obtain soft-state structure from function node */
-#define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data))
-
-/** Obtain soft-state structure from device node */
-#define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data))
 
 /** The number of bits of one data unit send by the serial port. */
@@ -179,8 +173,22 @@
 	/** The fibril mutex for synchronizing the access to the device. */
 	fibril_mutex_t mutex;
+	/** Indicates that some data has become available */
+	fibril_condvar_t input_buffer_available;
 	/** True if device is removed. */
 	bool removed;
 } ns8250_t;
 
+/** Obtain soft-state structure from device node */
+static ns8250_t *dev_ns8250(ddf_dev_t *dev)
+{
+	return ddf_dev_data_get(dev);
+}
+
+/** Obtain soft-state structure from function node */
+static ns8250_t *fun_ns8250(ddf_fun_t *fun)
+{
+	return dev_ns8250(ddf_fun_get_dev(fun));
+}
+
 /** Find out if there is some incomming data available on the serial port.
  *
@@ -237,8 +245,12 @@
 static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count)
 {
-	ns8250_t *ns = NS8250(fun);
-	int ret = EOK;
+	ns8250_t *ns = fun_ns8250(fun);
+	int ret = 0;
+	
+	if (count == 0) return 0;
 	
 	fibril_mutex_lock(&ns->mutex);
+	while (buf_is_empty(&ns->input_buffer))
+		fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
 	while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
 		buf[ret] = (char)buf_pop_front(&ns->input_buffer);
@@ -271,5 +283,5 @@
 static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count)
 {
-	ns8250_t *ns = NS8250(fun);
+	ns8250_t *ns = fun_ns8250(fun);
 	size_t idx;
 	
@@ -309,8 +321,4 @@
 static void ns8250_dev_cleanup(ns8250_t *ns)
 {
-	if (ns->dev->parent_sess) {
-		async_hangup(ns->dev->parent_sess);
-		ns->dev->parent_sess = NULL;
-	}
 }
 
@@ -322,5 +330,5 @@
 static bool ns8250_pio_enable(ns8250_t *ns)
 {
-	ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ns->dev->name);
+	ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ddf_dev_get_name(ns->dev));
 	
 	/* Gain control over port's registers. */
@@ -328,5 +336,5 @@
 	    (void **) &ns->port)) {
 		ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
-		    " for device %s.", ns->io_addr, ns->dev->name);
+		    " for device %s.", ns->io_addr, ddf_dev_get_name(ns->dev));
 		return false;
 	}
@@ -344,5 +352,5 @@
 static bool ns8250_dev_probe(ns8250_t *ns)
 {
-	ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ns->dev->name);
+	ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ddf_dev_get_name(ns->dev));
 	
 	bool res = true;
@@ -364,5 +372,5 @@
 	if (!res) {
 		ddf_msg(LVL_DEBUG, "Device %s is not present.",
-		    ns->dev->name);
+		    ddf_dev_get_name(ns->dev));
 	}
 	
@@ -377,7 +385,8 @@
 static int ns8250_dev_initialize(ns8250_t *ns)
 {
-	ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ns->dev->name);
-	
+	async_sess_t *parent_sess;
 	int ret = EOK;
+	
+	ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev));
 	
 	hw_resource_list_t hw_resources;
@@ -385,9 +394,8 @@
 	
 	/* Connect to the parent's driver. */
-	ns->dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
-	    ns->dev->handle, IPC_FLAG_BLOCKING);
-	if (!ns->dev->parent_sess) {
+	parent_sess = ddf_dev_parent_sess_create(ns->dev, EXCHANGE_SERIALIZE);
+	if (parent_sess == NULL) {
 		ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
-		    "device %s.", ns->dev->name);
+		    "device %s.", ddf_dev_get_name(ns->dev));
 		ret = ENOENT;
 		goto failed;
@@ -395,8 +403,8 @@
 	
 	/* Get hw resources. */
-	ret = hw_res_get_resource_list(ns->dev->parent_sess, &hw_resources);
+	ret = hw_res_get_resource_list(parent_sess, &hw_resources);
 	if (ret != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
-		    "%s.", ns->dev->name);
+		    "%s.", ddf_dev_get_name(ns->dev));
 		goto failed;
 	}
@@ -414,5 +422,5 @@
 			irq = true;
 			ddf_msg(LVL_NOTE, "Device %s was asigned irq = 0x%x.",
-			    ns->dev->name, ns->irq);
+			    ddf_dev_get_name(ns->dev), ns->irq);
 			break;
 			
@@ -421,5 +429,5 @@
 			if (res->res.io_range.size < REG_COUNT) {
 				ddf_msg(LVL_ERROR, "I/O range assigned to "
-				    "device %s is too small.", ns->dev->name);
+				    "device %s is too small.", ddf_dev_get_name(ns->dev));
 				ret = ELIMIT;
 				goto failed;
@@ -427,5 +435,5 @@
 			ioport = true;
 			ddf_msg(LVL_NOTE, "Device %s was asigned I/O address = "
-			    "0x%x.", ns->dev->name, ns->io_addr);
+			    "0x%x.", ddf_dev_get_name(ns->dev), ns->io_addr);
     			break;
 			
@@ -437,5 +445,5 @@
 	if (!irq || !ioport) {
 		ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
-		    ns->dev->name);
+		    ddf_dev_get_name(ns->dev));
 		ret = ENOENT;
 		goto failed;
@@ -460,5 +468,5 @@
 {
 	/* Interrupt when data received. */
-	pio_write_8(&regs->ier, NS8250_IER_RXREADY);
+	pio_write_8(&regs->ier, NS8250_IER_RXREADY | NS8250_IER_RXSTATUS);
 	pio_write_8(&regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS 
 	    | NS8250_MCR_OUT2);
@@ -499,4 +507,7 @@
 	async_exchange_end(exch);
 
+	/* Read LSR to clear possible previous LSR interrupt */
+	pio_read_8(&ns->regs->lsr);
+
 	/* Enable interrupt on the serial port. */
 	ns8250_port_interrupts_enable(ns->regs);
@@ -602,4 +613,7 @@
 	*parity = ((val >> NS8250_LCR_PARITY) & 7);
 	
+	/* Silence warnings */
+	*word_length = 0;
+
 	switch (val & 3) {
 	case WORD_LENGTH_5:
@@ -695,8 +709,11 @@
 	/* 8 bits, no parity, two stop bits. */
 	ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
-	/* Enable FIFO, clear them, with 14-byte threshold. */
+	/*
+	 * Enable FIFO, clear them, with 4-byte threshold for greater
+	 * reliability.
+	 */
 	pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE
-	    | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET 
-	    | NS8250_FCR_RXTRIGGERLOW | NS8250_FCR_RXTRIGGERHI);
+	    | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET
+	    | NS8250_FCR_RXTRIGGERLOW);
 	/*
 	 * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
@@ -731,7 +748,6 @@
 	bool cont = true;
 	
+	fibril_mutex_lock(&ns->mutex);
 	while (cont) {
-		fibril_mutex_lock(&ns->mutex);
-		
 		cont = ns8250_received(regs);
 		if (cont) {
@@ -739,24 +755,28 @@
 			
 			if (ns->client_connected) {
+				bool buf_was_empty = buf_is_empty(&ns->input_buffer);
 				if (!buf_push_back(&ns->input_buffer, val)) {
 					ddf_msg(LVL_WARN, "Buffer overflow on "
-					    "%s.", ns->dev->name);
+					    "%s.", ddf_dev_get_name(ns->dev));
+					break;
 				} else {
 					ddf_msg(LVL_DEBUG2, "Character %c saved "
 					    "to the buffer of %s.",
-					    val, ns->dev->name);
+					    val, ddf_dev_get_name(ns->dev));
+					if (buf_was_empty)
+						fibril_condvar_broadcast(&ns->input_buffer_available);
 				}
 			}
 		}
-		
-		fibril_mutex_unlock(&ns->mutex);
-		fibril_yield();
-	}
+	}
+	fibril_mutex_unlock(&ns->mutex);
+	fibril_yield();
 }
 
 /** The interrupt handler.
  *
- * The serial port is initialized to interrupt when some data come, so the
- * interrupt is handled by reading the incomming data.
+ * The serial port is initialized to interrupt when some data come or line
+ * status register changes, so the interrupt is handled by reading the incoming
+ * data and reading the line status register.
  *
  * @param dev		The serial port device.
@@ -765,5 +785,15 @@
     ipc_call_t *icall)
 {
-	ns8250_read_from_device(NS8250_FROM_DEV(dev));
+	ns8250_t *ns = dev_ns8250(dev);
+
+	uint8_t iir = pio_read_8(&ns->regs->iid);
+	if ((iir & NS8250_IID_CAUSE_MASK) == NS8250_IID_CAUSE_RXSTATUS) {
+		uint8_t lsr = pio_read_8(&ns->regs->lsr);
+		if (lsr & NS8250_LSR_OE) {
+			ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
+		}
+	}
+	
+	ns8250_read_from_device(ns);
 }
 
@@ -801,5 +831,5 @@
 	
 	ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)",
-	    dev->name, (int) dev->handle);
+	    ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
 	
 	/* Allocate soft-state for the device */
@@ -811,4 +841,5 @@
 	
 	fibril_mutex_initialize(&ns->mutex);
+	fibril_condvar_initialize(&ns->input_buffer_available);
 	ns->dev = dev;
 	
@@ -855,5 +886,5 @@
 	
 	/* Set device operations. */
-	fun->ops = &ns8250_dev_ops;
+	ddf_fun_set_ops(fun, &ns8250_dev_ops);
 	rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
@@ -867,5 +898,5 @@
 	
 	ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
-	    dev->name);
+	    ddf_dev_get_name(dev));
 	
 	return EOK;
@@ -880,5 +911,5 @@
 static int ns8250_dev_remove(ddf_dev_t *dev)
 {
-	ns8250_t *ns = NS8250_FROM_DEV(dev);
+	ns8250_t *ns = dev_ns8250(dev);
 	int rc;
 	
@@ -914,5 +945,5 @@
 static int ns8250_open(ddf_fun_t *fun)
 {
-	ns8250_t *ns = NS8250(fun);
+	ns8250_t *ns = fun_ns8250(fun);
 	int res;
 	
@@ -940,5 +971,5 @@
 static void ns8250_close(ddf_fun_t *fun)
 {
-	ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
+	ns8250_t *data = fun_ns8250(fun);
 	
 	fibril_mutex_lock(&data->mutex);
@@ -965,5 +996,5 @@
     unsigned int *word_length, unsigned int* stop_bits)
 {
-	ns8250_t *data = (ns8250_t *) dev->driver_data;
+	ns8250_t *data = dev_ns8250(dev);
 	ns8250_regs_t *regs = data->regs;
 	
@@ -996,5 +1027,5 @@
 	    stop_bits);
 	
-	ns8250_t *data = (ns8250_t *) dev->driver_data;
+	ns8250_t *data = dev_ns8250(dev);
 	ns8250_regs_t *regs = data->regs;
 	int ret;
@@ -1025,5 +1056,5 @@
 	switch (method) {
 	case SERIAL_GET_COM_PROPS:
-		ns8250_get_props(fun->dev, &baud_rate, &parity, &word_length,
+		ns8250_get_props(ddf_fun_get_dev(fun), &baud_rate, &parity, &word_length,
 		    &stop_bits);
 		async_answer_4(callid, EOK, baud_rate, parity, word_length,
@@ -1036,5 +1067,5 @@
 		word_length = IPC_GET_ARG3(*call);
 		stop_bits = IPC_GET_ARG4(*call);
-		ret = ns8250_set_props(fun->dev, baud_rate, parity, word_length,
+		ret = ns8250_set_props(ddf_fun_get_dev(fun), baud_rate, parity, word_length,
 		    stop_bits);
 		async_answer_0(callid, ret);
@@ -1053,5 +1084,5 @@
 static void ns8250_init(void)
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME, LVL_WARN);
 	
 	ns8250_dev_ops.open = &ns8250_open;
