Hi all,
I'm applying to HelenOS at GSoC 2012. My proposition is to write AMD
Lance AM7990 (and clones) Ethernet controller driver. I've actually done
a small patch for ticket #262, it replaces ns8250.c "magic numbers" with
structured register definitions. This patch was successfully tested
using slightly modified "tester serial1" command. Please let me know if
attached patch is correct.
Regards,
Adrian.
=== modified file 'uspace/drv/char/ns8250/ns8250.c'
--- uspace/drv/char/ns8250/ns8250.c 2011-11-14 20:50:08 +0000
+++ uspace/drv/char/ns8250/ns8250.c 2012-04-05 11:24:32 +0000
@@ -73,6 +73,58 @@
#define MAX_BAUD_RATE 115200
#define DLAB_MASK (1 << 7)
+/** Interrupt Enable Register definition. */
+#define NS8250_IER_RXREADY (1 << 0)
+#define NS8250_IER_THRE (1 << 1)
+#define NS8250_IER_RXSTATUS (1 << 2)
+#define NS8250_IER_MODEM_STATUS (1 << 3)
+
+/** Interrupt ID Register definition. */
+#define NS8250_IID_ACTIVE (1 << 0)
+
+/** FIFO Control Register definition. */
+#define NS8250_FCR_FIFOENABLE (1 << 0)
+#define NS8250_FCR_RXFIFORESET (1 << 1)
+#define NS8250_FCR_TXFIFORESET (1 << 2)
+#define NS8250_FCR_DMAMODE (1 << 3)
+#define NS8250_FCR_RXTRIGGERLOW (1 << 6)
+#define NS8250_FCR_RXTRIGGERHI (1 << 7)
+
+/** Line Control Register definition. */
+#define NS8250_LCR_STOPBITS (1 << 2)
+#define NS8250_LCR_PARITY (1 << 3)
+#define NS8250_LCR_SENDBREAK (1 << 6)
+#define NS8250_LCR_DLAB (1 << 7)
+
+/** Modem Control Register definition. */
+#define NS8250_MCR_DTR (1 << 0)
+#define NS8250_MCR_RTS (1 << 1)
+#define NS8250_MCR_OUT1 (1 << 2)
+#define NS8250_MCR_OUT2 (1 << 3)
+#define NS8250_MCR_LOOPBACK (1 << 4)
+#define NS8250_MCR_ALL (0x1f)
+
+/** Line Status Register definition. */
+#define NS8250_LSR_RXREADY (1 << 0)
+#define NS8250_LSR_OE (1 << 1)
+#define NS8250_LSR_PE (1 << 2)
+#define NS8250_LSR_FE (1 << 3)
+#define NS8250_LSR_BREAK (1 << 4)
+#define NS8250_LSR_THRE (1 << 5)
+#define NS8250_LSR_TSE (1 << 6)
+
+/** Modem Status Register definition. */
+#define NS8250_MSR_DELTACTS (1 << 0)
+#define NS8250_MSR_DELTADSR (1 << 1)
+#define NS8250_MSR_RITRAILING (1 << 2)
+#define NS8250_MSR_DELTADCD (1 << 3)
+#define NS8250_MSR_CTS (1 << 4)
+#define NS8250_MSR_DSR (1 << 5)
+#define NS8250_MSR_RI (1 << 6)
+#define NS8250_MSR_DCD (1 << 7)
+#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))
@@ -95,12 +147,25 @@
TWO_STOP_BITS
} stop_bit_t;
+/** 8250 UART registers layout. */
+typedef struct {
+ ioport8_t data; /**< Data register. */
+ ioport8_t ier; /**< Interrupt Enable Reg. */
+ ioport8_t iid; /**< Interrupt ID Reg. */
+ ioport8_t lcr; /**< Line Control Reg. */
+ ioport8_t mcr; /**< Modem Control Reg. */
+ ioport8_t lsr; /**< Line Status Reg. */
+ ioport8_t msr; /**< Modem Status Reg. */
+} __attribute__ ((packed)) ns8250_regs_t;
+
/** The driver data for the serial port devices. */
typedef struct ns8250 {
/** DDF device node */
ddf_dev_t *dev;
/** DDF function node */
ddf_fun_t *fun;
+ /** I/O registers **/
+ ns8250_regs_t *regs;
/** Is there any client conntected to the device? */
bool client_connected;
/** The irq assigned to this device. */
@@ -123,9 +188,9 @@
* @return True if there are data waiting to be read, false
* otherwise.
*/
-static bool ns8250_received(ioport8_t *port)
+static bool ns8250_received(ns8250_regs_t *regs)
{
- return (pio_read_8(port + 5) & 1) != 0;
+ return (pio_read_8(®s->lsr) & NS8250_LSR_RXREADY) != 0;
}
/** Read one byte from the serial port.
@@ -133,18 +198,18 @@
* @param port The base address of the serial port device's ports.
* @return The data read.
*/
-static uint8_t ns8250_read_8(ioport8_t *port)
+static uint8_t ns8250_read_8(ns8250_regs_t *regs)
{
- return pio_read_8(port);
+ return pio_read_8(®s->data);
}
/** Find out wheter it is possible to send data.
*
* @param port The base address of the serial port device's ports.
*/
-static bool is_transmit_empty(ioport8_t *port)
+static bool is_transmit_empty(ns8250_regs_t *regs)
{
- return (pio_read_8(port + 5) & 0x20) != 0;
+ return (pio_read_8(®s->lsr) & NS8250_LSR_THRE) != 0;
}
/** Write one character on the serial port.
@@ -152,12 +217,12 @@
* @param port The base address of the serial port device's ports.
* @param c The character to be written to the serial port device.
*/
-static void ns8250_write_8(ioport8_t *port, uint8_t c)
+static void ns8250_write_8(ns8250_regs_t *regs, uint8_t c)
{
- while (!is_transmit_empty(port))
+ while (!is_transmit_empty(regs))
;
- pio_write_8(port, c);
+ pio_write_8(®s->data, c);
}
/** Read data from the serial port device.
@@ -192,7 +257,7 @@
static inline void ns8250_putchar(ns8250_t *ns, uint8_t c)
{
fibril_mutex_lock(&ns->mutex);
- ns8250_write_8(ns->port, c);
+ ns8250_write_8(ns->regs, c);
fibril_mutex_unlock(&ns->mutex);
}
@@ -265,6 +330,8 @@
" for device %s.", ns->io_addr, ns->dev->name);
return false;
}
+
+ ns->regs = (ns8250_regs_t *)ns->port;
return true;
}
@@ -278,21 +345,21 @@
{
ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ns->dev->name);
- ioport8_t *port_addr = ns->port;
bool res = true;
uint8_t olddata;
- olddata = pio_read_8(port_addr + 4);
-
- pio_write_8(port_addr + 4, 0x10);
- if (pio_read_8(port_addr + 6) & 0xf0)
- res = false;
-
- pio_write_8(port_addr + 4, 0x1f);
- if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0)
- res = false;
-
- pio_write_8(port_addr + 4, olddata);
+ olddata = pio_read_8(&ns->regs->mcr);
+
+ pio_write_8(&ns->regs->mcr, NS8250_MCR_LOOPBACK);
+ if (pio_read_8(&ns->regs->msr) & NS8250_MSR_SIGNALS)
+ res = false;
+
+ pio_write_8(&ns->regs->mcr, NS8250_MCR_ALL);
+ if ((pio_read_8(&ns->regs->msr) & NS8250_MSR_SIGNALS)
+ != NS8250_MSR_SIGNALS)
+ res = false;
+
+ pio_write_8(&ns->regs->mcr, olddata);
if (!res) {
ddf_msg(LVL_DEBUG, "Device %s is not present.",
@@ -389,19 +456,21 @@
*
* @param port The base address of the serial port device's ports.
*/
-static inline void ns8250_port_interrupts_enable(ioport8_t *port)
+static inline void ns8250_port_interrupts_enable(ns8250_regs_t *regs)
{
- pio_write_8(port + 1, 0x1); /* Interrupt when data received. */
- pio_write_8(port + 4, 0xB);
+ /* Interrupt when data received. */
+ pio_write_8(®s->ier, NS8250_IER_RXREADY);
+ pio_write_8(®s->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS
+ | NS8250_MCR_OUT2);
}
/** Disable interrupts on the serial port device.
*
* @param port The base address of the serial port device's ports
*/
-static inline void ns8250_port_interrupts_disable(ioport8_t *port)
+static inline void ns8250_port_interrupts_disable(ns8250_regs_t *regs)
{
- pio_write_8(port + 1, 0x0); /* Disable all interrupts. */
+ pio_write_8(®s->ier, 0x0); /* Disable all interrupts. */
}
/** Enable interrupts for the serial port device.
@@ -430,7 +499,7 @@
async_exchange_end(exch);
/* Enable interrupt on the serial port. */
- ns8250_port_interrupts_enable(ns->port);
+ ns8250_port_interrupts_enable(ns->regs);
return EOK;
}
@@ -442,20 +511,20 @@
*
* @param port The base address of the serial port device's ports.
*/
-static inline void enable_dlab(ioport8_t *port)
+static inline void enable_dlab(ns8250_regs_t *regs)
{
- uint8_t val = pio_read_8(port + 3);
- pio_write_8(port + 3, val | DLAB_MASK);
+ uint8_t val = pio_read_8(®s->lcr);
+ pio_write_8(®s->lcr, val | NS8250_LCR_DLAB);
}
/** Clear Divisor Latch Access Bit.
*
* @param port The base address of the serial port device's ports.
*/
-static inline void clear_dlab(ioport8_t *port)
+static inline void clear_dlab(ns8250_regs_t *regs)
{
- uint8_t val = pio_read_8(port + 3);
- pio_write_8(port + 3, val & (~DLAB_MASK));
+ uint8_t val = pio_read_8(®s->lcr);
+ pio_write_8(®s->lcr, val & (~NS8250_LCR_DLAB));
}
/** Set baud rate of the serial communication on the serial device.
@@ -465,7 +534,7 @@
* @return Zero on success, negative error number otherwise (EINVAL
* if the specified baud_rate is not valid).
*/
-static int ns8250_port_set_baud_rate(ioport8_t *port, unsigned int baud_rate)
+static int ns8250_port_set_baud_rate(ns8250_regs_t *regs, unsigned int baud_rate)
{
uint16_t divisor;
uint8_t div_low, div_high;
@@ -481,14 +550,14 @@
div_high = (uint8_t)(divisor >> 8);
/* Enable DLAB to be able to access baud rate divisor. */
- enable_dlab(port);
+ enable_dlab(regs);
/* Set divisor low byte. */
- pio_write_8(port + 0, div_low);
+ pio_write_8(®s->data, div_low);
/* Set divisor high byte. */
- pio_write_8(port + 1, div_high);
+ pio_write_8(®s->ier, div_high);
- clear_dlab(port);
+ clear_dlab(regs);
return EOK;
}
@@ -498,20 +567,20 @@
* @param port The base address of the serial port device's ports.
* @param baud_rate The ouput parameter to which the baud rate is stored.
*/
-static unsigned int ns8250_port_get_baud_rate(ioport8_t *port)
+static unsigned int ns8250_port_get_baud_rate(ns8250_regs_t *regs)
{
uint16_t divisor;
uint8_t div_low, div_high;
/* Enable DLAB to be able to access baud rate divisor. */
- enable_dlab(port);
+ enable_dlab(regs);
/* Get divisor low byte. */
- div_low = pio_read_8(port + 0);
+ div_low = pio_read_8(®s->data);
/* Get divisor high byte. */
- div_high = pio_read_8(port + 1);
+ div_high = pio_read_8(®s->ier);
- clear_dlab(port);
+ clear_dlab(regs);
divisor = (div_high << 8) | div_low;
return MAX_BAUD_RATE / divisor;
@@ -524,13 +593,13 @@
* @param word_length The length of one data unit in bits.
* @param stop_bits The number of stop bits used (one or two).
*/
-static void ns8250_port_get_com_props(ioport8_t *port, unsigned int *parity,
+static void ns8250_port_get_com_props(ns8250_regs_t *regs, unsigned int *parity,
unsigned int *word_length, unsigned int *stop_bits)
{
uint8_t val;
- val = pio_read_8(port + 3);
- *parity = ((val >> 3) & 7);
+ val = pio_read_8(®s->lcr);
+ *parity = ((val >> NS8250_LCR_PARITY) & 7);
switch (val & 3) {
case WORD_LENGTH_5:
@@ -547,7 +616,7 @@
break;
}
- if ((val >> 2) & 1)
+ if ((val >> NS8250_LCR_STOPBITS) & 1)
*stop_bits = 2;
else
*stop_bits = 1;
@@ -561,7 +630,7 @@
* @return Zero on success, EINVAL if some of the specified values
* is invalid.
*/
-static int ns8250_port_set_com_props(ioport8_t *port, unsigned int parity,
+static int ns8250_port_set_com_props(ns8250_regs_t *regs, unsigned int parity,
unsigned int word_length, unsigned int stop_bits)
{
uint8_t val;
@@ -585,10 +654,10 @@
switch (stop_bits) {
case 1:
- val |= ONE_STOP_BIT << 2;
+ val |= ONE_STOP_BIT << NS8250_LCR_STOPBITS;
break;
case 2:
- val |= TWO_STOP_BITS << 2;
+ val |= TWO_STOP_BITS << NS8250_LCR_STOPBITS;
break;
default:
return EINVAL;
@@ -600,13 +669,13 @@
case SERIAL_EVEN_PARITY:
case SERIAL_MARK_PARITY:
case SERIAL_SPACE_PARITY:
- val |= parity << 3;
+ val |= parity << NS8250_LCR_PARITY;
break;
default:
return EINVAL;
}
- pio_write_8(port + 3, val);
+ pio_write_8(®s->lcr, val);
return EOK;
}
@@ -619,21 +688,22 @@
*/
static void ns8250_initialize_port(ns8250_t *ns)
{
- ioport8_t *port = ns->port;
-
/* Disable interrupts. */
- ns8250_port_interrupts_disable(port);
+ ns8250_port_interrupts_disable(ns->regs);
/* Set baud rate. */
- ns8250_port_set_baud_rate(port, 38400);
+ ns8250_port_set_baud_rate(ns->regs, 38400);
/* 8 bits, no parity, two stop bits. */
- ns8250_port_set_com_props(port, SERIAL_NO_PARITY, 8, 2);
+ ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
/* Enable FIFO, clear them, with 14-byte threshold. */
- pio_write_8(port + 2, 0xC7);
+ pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE
+ | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET
+ | NS8250_FCR_RXTRIGGERLOW | NS8250_FCR_RXTRIGGERHI);
/*
* RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
* Aux Output2 set - needed for interrupts.
*/
- pio_write_8(port + 4, 0x0B);
+ pio_write_8(&ns->regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS
+ | NS8250_MCR_OUT2);
}
/** Deinitialize the serial port device.
@@ -643,11 +713,11 @@
static void ns8250_port_cleanup(ns8250_t *ns)
{
/* Disable FIFO */
- pio_write_8(ns->port + 2, 0x00);
+ pio_write_8(&ns->regs->iid, 0x00);
/* Disable DTR, RTS, OUT1, OUT2 (int. enable) */
- pio_write_8(ns->port + 4, 0x00);
+ pio_write_8(&ns->regs->mcr, 0x00);
/* Disable all interrupts from the port */
- ns8250_port_interrupts_disable(ns->port);
+ ns8250_port_interrupts_disable(ns->regs);
}
/** Read the data from the serial port device and store them to the input
@@ -657,15 +727,15 @@
*/
static void ns8250_read_from_device(ns8250_t *ns)
{
- ioport8_t *port = ns->port;
+ ns8250_regs_t *regs = ns->regs;
bool cont = true;
while (cont) {
fibril_mutex_lock(&ns->mutex);
- cont = ns8250_received(port);
+ cont = ns8250_received(regs);
if (cont) {
- uint8_t val = ns8250_read_8(port);
+ uint8_t val = ns8250_read_8(regs);
if (ns->client_connected) {
if (!buf_push_back(&ns->input_buffer, val)) {
@@ -895,13 +965,13 @@
unsigned int *word_length, unsigned int* stop_bits)
{
ns8250_t *data = (ns8250_t *) dev->driver_data;
- ioport8_t *port = data->port;
+ ns8250_regs_t *regs = data->regs;
fibril_mutex_lock(&data->mutex);
- ns8250_port_interrupts_disable(port);
- *baud_rate = ns8250_port_get_baud_rate(port);
- ns8250_port_get_com_props(port, parity, word_length, stop_bits);
- ns8250_port_interrupts_enable(port);
+ ns8250_port_interrupts_disable(regs);
+ *baud_rate = ns8250_port_get_baud_rate(regs);
+ ns8250_port_get_com_props(regs, parity, word_length, stop_bits);
+ ns8250_port_interrupts_enable(regs);
fibril_mutex_unlock(&data->mutex);
ddf_msg(LVL_DEBUG, "ns8250_get_props: baud rate %d, parity 0x%x, word "
@@ -926,15 +996,15 @@
stop_bits);
ns8250_t *data = (ns8250_t *) dev->driver_data;
- ioport8_t *port = data->port;
+ ns8250_regs_t *regs = data->regs;
int ret;
fibril_mutex_lock(&data->mutex);
- ns8250_port_interrupts_disable(port);
- ret = ns8250_port_set_baud_rate(port, baud_rate);
+ ns8250_port_interrupts_disable(regs);
+ ret = ns8250_port_set_baud_rate(regs, baud_rate);
if (ret == EOK)
- ret = ns8250_port_set_com_props(port, parity, word_length, stop_bits);
- ns8250_port_interrupts_enable(port);
+ ret = ns8250_port_set_com_props(regs, parity, word_length, stop_bits);
+ ns8250_port_interrupts_enable(regs);
fibril_mutex_unlock(&data->mutex);
return ret;
_______________________________________________
HelenOS-devel mailing list
[email protected]
http://lists.modry.cz/cgi-bin/listinfo/helenos-devel