HelenOS sources
This source file includes following definitions.
- dev_ns8250
- fun_ns8250
- srv_ns8250
- ns8250_received
- ns8250_read_8
- is_transmit_empty
- ns8250_write_8
- ns8250_read
- ns8250_putchar
- ns8250_write
- ns8250_dev_cleanup
- ns8250_pio_enable
- ns8250_dev_probe
- ns8250_dev_initialize
- ns8250_port_interrupts_enable
- ns8250_port_interrupts_disable
- ns8250_interrupt_enable
- enable_dlab
- clear_dlab
- ns8250_port_set_baud_rate
- ns8250_port_get_baud_rate
- ns8250_port_get_com_props
- ns8250_port_set_com_props
- ns8250_initialize_port
- ns8250_port_cleanup
- ns8250_read_from_device
- ns8250_interrupt_handler
- ns8250_register_interrupt_handler
- ns8250_unregister_interrupt_handler
- ns8250_dev_add
- ns8250_dev_remove
- ns8250_open
- ns8250_close
- ns8250_get_props
- ns8250_set_props
- ns8250_default_handler
- ns8250_char_conn
- ns8250_init
- main
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <str_error.h>
#include <stdbool.h>
#include <fibril_synch.h>
#include <stdlib.h>
#include <str.h>
#include <ctype.h>
#include <macros.h>
#include <stdlib.h>
#include <dirent.h>
#include <ddi.h>
#include <ddf/driver.h>
#include <ddf/interrupt.h>
#include <ddf/log.h>
#include <io/chardev_srv.h>
#include <device/hw_res.h>
#include <ipc/serial_ctl.h>
#include "cyclic_buffer.h"
#define NAME "ns8250"
#define REG_COUNT 7
#define MAX_BAUD_RATE 115200
#define DLAB_MASK (1 << 7)
#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)
#define NS8250_IID_ACTIVE (1 << 0)
#define NS8250_IID_CAUSE_MASK 0x0e
#define NS8250_IID_CAUSE_RXSTATUS 0x06
#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)
#define NS8250_LCR_STOPBITS (1 << 2)
#define NS8250_LCR_PARITY (1 << 3)
#define NS8250_LCR_SENDBREAK (1 << 6)
#define NS8250_LCR_DLAB (1 << 7)
#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)
#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)
#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)
typedef enum {
WORD_LENGTH_5,
WORD_LENGTH_6,
WORD_LENGTH_7,
WORD_LENGTH_8
} word_length_t;
typedef enum {
ONE_STOP_BIT,
TWO_STOP_BITS
} stop_bit_t;
typedef struct {
ioport8_t data;
ioport8_t ier;
ioport8_t iid;
ioport8_t lcr;
ioport8_t mcr;
ioport8_t lsr;
ioport8_t msr;
} ns8250_regs_t;
typedef struct ns8250 {
ddf_dev_t *dev;
ddf_fun_t *fun;
chardev_srvs_t cds;
async_sess_t *parent_sess;
ns8250_regs_t *regs;
unsigned client_connections;
int irq;
cap_irq_handle_t irq_handle;
uintptr_t io_addr;
ioport8_t *port;
cyclic_buffer_t input_buffer;
fibril_mutex_t mutex;
fibril_condvar_t input_buffer_available;
bool removed;
} ns8250_t;
static ns8250_t *dev_ns8250(ddf_dev_t *dev)
{
return ddf_dev_data_get(dev);
}
static ns8250_t *fun_ns8250(ddf_fun_t *fun)
{
return dev_ns8250(ddf_fun_get_dev(fun));
}
static ns8250_t *srv_ns8250(chardev_srv_t *srv)
{
return (ns8250_t *)srv->srvs->sarg;
}
static bool ns8250_received(ns8250_regs_t *regs)
{
return (pio_read_8(®s->lsr) & NS8250_LSR_RXREADY) != 0;
}
static uint8_t ns8250_read_8(ns8250_regs_t *regs)
{
return pio_read_8(®s->data);
}
static bool is_transmit_empty(ns8250_regs_t *regs)
{
return (pio_read_8(®s->lsr) & NS8250_LSR_THRE) != 0;
}
static void ns8250_write_8(ns8250_regs_t *regs, uint8_t c)
{
while (!is_transmit_empty(regs))
;
pio_write_8(®s->data, c);
}
static errno_t ns8250_read(chardev_srv_t *srv, void *buf, size_t count, size_t *nread,
chardev_flags_t flags)
{
ns8250_t *ns = srv_ns8250(srv);
char *bp = (char *) buf;
size_t pos = 0;
if (count == 0) {
*nread = 0;
return EOK;
}
fibril_mutex_lock(&ns->mutex);
while ((flags & chardev_f_none) == 0 &&
buf_is_empty(&ns->input_buffer))
fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
while (!buf_is_empty(&ns->input_buffer) && pos < count) {
bp[pos] = (char)buf_pop_front(&ns->input_buffer);
pos++;
}
fibril_mutex_unlock(&ns->mutex);
*nread = pos;
return EOK;
}
static inline void ns8250_putchar(ns8250_t *ns, uint8_t c)
{
fibril_mutex_lock(&ns->mutex);
ns8250_write_8(ns->regs, c);
fibril_mutex_unlock(&ns->mutex);
}
static errno_t ns8250_write(chardev_srv_t *srv, const void *buf, size_t count,
size_t *nwritten)
{
ns8250_t *ns = srv_ns8250(srv);
size_t idx;
uint8_t *bp = (uint8_t *) buf;
for (idx = 0; idx < count; idx++)
ns8250_putchar(ns, bp[idx]);
*nwritten = count;
return EOK;
}
static errno_t ns8250_open(chardev_srvs_t *, chardev_srv_t *);
static errno_t ns8250_close(chardev_srv_t *);
static void ns8250_default_handler(chardev_srv_t *, ipc_call_t *);
static chardev_ops_t ns8250_chardev_ops = {
.open = ns8250_open,
.close = ns8250_close,
.read = ns8250_read,
.write = ns8250_write,
.def_handler = ns8250_default_handler
};
static void ns8250_char_conn(ipc_call_t *, void *);
static errno_t ns8250_dev_add(ddf_dev_t *dev);
static errno_t ns8250_dev_remove(ddf_dev_t *dev);
static driver_ops_t ns8250_ops = {
.dev_add = &ns8250_dev_add,
.dev_remove = &ns8250_dev_remove
};
static driver_t ns8250_driver = {
.name = NAME,
.driver_ops = &ns8250_ops
};
static void ns8250_dev_cleanup(ns8250_t *ns)
{
}
static bool ns8250_pio_enable(ns8250_t *ns)
{
ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ddf_dev_get_name(ns->dev));
if (pio_enable((void *) ns->io_addr, REG_COUNT,
(void **) &ns->port)) {
ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIxn
" for device %s.", ns->io_addr, ddf_dev_get_name(ns->dev));
return false;
}
ns->regs = (ns8250_regs_t *)ns->port;
return true;
}
static bool ns8250_dev_probe(ns8250_t *ns)
{
ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ddf_dev_get_name(ns->dev));
bool res = true;
uint8_t 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.",
ddf_dev_get_name(ns->dev));
}
return res;
}
static errno_t ns8250_dev_initialize(ns8250_t *ns)
{
errno_t ret = EOK;
ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev));
hw_resource_list_t hw_resources;
memset(&hw_resources, 0, sizeof(hw_resource_list_t));
ret = hw_res_get_resource_list(ns->parent_sess, &hw_resources);
if (ret != EOK) {
ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
"%s.", ddf_dev_get_name(ns->dev));
goto failed;
}
size_t i;
hw_resource_t *res;
bool irq = false;
bool ioport = false;
for (i = 0; i < hw_resources.count; i++) {
res = &hw_resources.resources[i];
switch (res->type) {
case INTERRUPT:
ns->irq = res->res.interrupt.irq;
irq = true;
ddf_msg(LVL_NOTE, "Device %s was assigned irq = 0x%x.",
ddf_dev_get_name(ns->dev), ns->irq);
break;
case IO_RANGE:
ns->io_addr = res->res.io_range.address;
if (res->res.io_range.size < REG_COUNT) {
ddf_msg(LVL_ERROR, "I/O range assigned to "
"device %s is too small.", ddf_dev_get_name(ns->dev));
ret = ELIMIT;
goto failed;
}
ioport = true;
ddf_msg(LVL_NOTE, "Device %s was assigned I/O address = "
"0x%#" PRIxn ".", ddf_dev_get_name(ns->dev), ns->io_addr);
break;
default:
break;
}
}
if (!irq || !ioport) {
ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
ddf_dev_get_name(ns->dev));
ret = ENOENT;
goto failed;
}
hw_res_clean_resource_list(&hw_resources);
return ret;
failed:
ns8250_dev_cleanup(ns);
hw_res_clean_resource_list(&hw_resources);
return ret;
}
static inline void ns8250_port_interrupts_enable(ns8250_regs_t *regs)
{
pio_write_8(®s->ier, NS8250_IER_RXREADY | NS8250_IER_RXSTATUS);
pio_write_8(®s->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS |
NS8250_MCR_OUT2);
}
static inline void ns8250_port_interrupts_disable(ns8250_regs_t *regs)
{
pio_write_8(®s->ier, 0x0);
}
static errno_t ns8250_interrupt_enable(ns8250_t *ns)
{
errno_t rc = hw_res_enable_interrupt(ns->parent_sess, ns->irq);
if (rc != EOK)
return EIO;
pio_read_8(&ns->regs->lsr);
ns8250_port_interrupts_enable(ns->regs);
return EOK;
}
static inline void enable_dlab(ns8250_regs_t *regs)
{
uint8_t val = pio_read_8(®s->lcr);
pio_write_8(®s->lcr, val | NS8250_LCR_DLAB);
}
static inline void clear_dlab(ns8250_regs_t *regs)
{
uint8_t val = pio_read_8(®s->lcr);
pio_write_8(®s->lcr, val & (~NS8250_LCR_DLAB));
}
static errno_t ns8250_port_set_baud_rate(ns8250_regs_t *regs, unsigned int baud_rate)
{
uint16_t divisor;
uint8_t div_low, div_high;
if (baud_rate < 50 || MAX_BAUD_RATE % baud_rate != 0) {
ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
baud_rate);
return EINVAL;
}
divisor = MAX_BAUD_RATE / baud_rate;
div_low = (uint8_t)divisor;
div_high = (uint8_t)(divisor >> 8);
enable_dlab(regs);
pio_write_8(®s->data, div_low);
pio_write_8(®s->ier, div_high);
clear_dlab(regs);
return EOK;
}
static unsigned int ns8250_port_get_baud_rate(ns8250_regs_t *regs)
{
uint16_t divisor;
uint8_t div_low, div_high;
enable_dlab(regs);
div_low = pio_read_8(®s->data);
div_high = pio_read_8(®s->ier);
clear_dlab(regs);
divisor = (div_high << 8) | div_low;
return MAX_BAUD_RATE / divisor;
}
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(®s->lcr);
*parity = ((val >> NS8250_LCR_PARITY) & 7);
*word_length = 0;
switch (val & 3) {
case WORD_LENGTH_5:
*word_length = 5;
break;
case WORD_LENGTH_6:
*word_length = 6;
break;
case WORD_LENGTH_7:
*word_length = 7;
break;
case WORD_LENGTH_8:
*word_length = 8;
break;
}
if ((val >> NS8250_LCR_STOPBITS) & 1)
*stop_bits = 2;
else
*stop_bits = 1;
}
static errno_t ns8250_port_set_com_props(ns8250_regs_t *regs, unsigned int parity,
unsigned int word_length, unsigned int stop_bits)
{
uint8_t val;
switch (word_length) {
case 5:
val = WORD_LENGTH_5;
break;
case 6:
val = WORD_LENGTH_6;
break;
case 7:
val = WORD_LENGTH_7;
break;
case 8:
val = WORD_LENGTH_8;
break;
default:
return EINVAL;
}
switch (stop_bits) {
case 1:
val |= ONE_STOP_BIT << NS8250_LCR_STOPBITS;
break;
case 2:
val |= TWO_STOP_BITS << NS8250_LCR_STOPBITS;
break;
default:
return EINVAL;
}
switch (parity) {
case SERIAL_NO_PARITY:
case SERIAL_ODD_PARITY:
case SERIAL_EVEN_PARITY:
case SERIAL_MARK_PARITY:
case SERIAL_SPACE_PARITY:
val |= parity << NS8250_LCR_PARITY;
break;
default:
return EINVAL;
}
pio_write_8(®s->lcr, val);
return EOK;
}
static void ns8250_initialize_port(ns8250_t *ns)
{
ns8250_port_interrupts_disable(ns->regs);
ns8250_port_set_baud_rate(ns->regs, 38400);
ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE |
NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET |
NS8250_FCR_RXTRIGGERLOW);
pio_write_8(&ns->regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS |
NS8250_MCR_OUT2);
}
static void ns8250_port_cleanup(ns8250_t *ns)
{
pio_write_8(&ns->regs->iid, 0x00);
pio_write_8(&ns->regs->mcr, 0x00);
ns8250_port_interrupts_disable(ns->regs);
}
static void ns8250_read_from_device(ns8250_t *ns)
{
ns8250_regs_t *regs = ns->regs;
bool cont = true;
fibril_mutex_lock(&ns->mutex);
while (cont) {
cont = ns8250_received(regs);
if (cont) {
uint8_t val = ns8250_read_8(regs);
if (ns->client_connections > 0) {
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.", ddf_dev_get_name(ns->dev));
break;
} else {
ddf_msg(LVL_DEBUG2, "Character %c saved "
"to the buffer of %s.",
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();
}
static inline void ns8250_interrupt_handler(ipc_call_t *icall, void *arg)
{
ns8250_t *ns = (ns8250_t *)arg;
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);
hw_res_clear_interrupt(ns->parent_sess, ns->irq);
}
static inline errno_t ns8250_register_interrupt_handler(ns8250_t *ns,
cap_irq_handle_t *ihandle)
{
return register_interrupt_handler(ns->dev, ns->irq,
ns8250_interrupt_handler, (void *)ns, NULL, ihandle);
}
static inline errno_t ns8250_unregister_interrupt_handler(ns8250_t *ns)
{
return unregister_interrupt_handler(ns->dev, ns->irq_handle);
}
static errno_t ns8250_dev_add(ddf_dev_t *dev)
{
ns8250_t *ns = NULL;
ddf_fun_t *fun = NULL;
bool need_cleanup = false;
bool need_unreg_intr_handler = false;
bool bound = false;
errno_t rc;
ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)",
ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
ns = ddf_dev_data_alloc(dev, sizeof(ns8250_t));
if (ns == NULL) {
rc = ENOMEM;
goto fail;
}
fibril_mutex_initialize(&ns->mutex);
fibril_condvar_initialize(&ns->input_buffer_available);
ns->dev = dev;
ns->parent_sess = ddf_dev_parent_sess_get(ns->dev);
if (ns->parent_sess == NULL) {
ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
"device %s.", ddf_dev_get_name(ns->dev));
rc = EIO;
goto fail;
}
rc = ns8250_dev_initialize(ns);
if (rc != EOK)
goto fail;
need_cleanup = true;
if (!ns8250_pio_enable(ns)) {
rc = EADDRNOTAVAIL;
goto fail;
}
if (!ns8250_dev_probe(ns)) {
rc = ENOENT;
goto fail;
}
ns8250_initialize_port(ns);
ns->irq_handle = CAP_NIL;
rc = ns8250_register_interrupt_handler(ns, &ns->irq_handle);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
rc = EADDRNOTAVAIL;
goto fail;
}
need_unreg_intr_handler = true;
rc = ns8250_interrupt_enable(ns);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
"%s.", str_error_name(rc));
goto fail;
}
fun = ddf_fun_create(dev, fun_exposed, "a");
if (fun == NULL) {
ddf_msg(LVL_ERROR, "Failed creating function.");
goto fail;
}
ddf_fun_set_conn_handler(fun, ns8250_char_conn);
chardev_srvs_init(&ns->cds);
ns->cds.ops = &ns8250_chardev_ops;
ns->cds.sarg = ns;
rc = ddf_fun_bind(fun);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed binding function.");
goto fail;
}
bound = true;
ns->fun = fun;
rc = ddf_fun_add_to_category(fun, "serial");
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Error adding function to category 'serial'.");
goto fail;
}
ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
ddf_dev_get_name(dev));
return EOK;
fail:
if (bound)
ddf_fun_unbind(fun);
if (fun != NULL)
ddf_fun_destroy(fun);
if (need_unreg_intr_handler)
ns8250_unregister_interrupt_handler(ns);
if (need_cleanup)
ns8250_dev_cleanup(ns);
return rc;
}
static errno_t ns8250_dev_remove(ddf_dev_t *dev)
{
ns8250_t *ns = dev_ns8250(dev);
errno_t rc;
fibril_mutex_lock(&ns->mutex);
if (ns->client_connections > 0) {
fibril_mutex_unlock(&ns->mutex);
return EBUSY;
}
ns->removed = true;
fibril_mutex_unlock(&ns->mutex);
rc = ddf_fun_unbind(ns->fun);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed to unbind function.");
return rc;
}
ddf_fun_destroy(ns->fun);
ns8250_port_cleanup(ns);
ns8250_unregister_interrupt_handler(ns);
ns8250_dev_cleanup(ns);
return EOK;
}
static errno_t ns8250_open(chardev_srvs_t *srvs, chardev_srv_t *srv)
{
ns8250_t *ns = srv_ns8250(srv);
errno_t res;
fibril_mutex_lock(&ns->mutex);
if (ns->removed) {
res = ENXIO;
} else {
res = EOK;
ns->client_connections++;
}
fibril_mutex_unlock(&ns->mutex);
return res;
}
static errno_t ns8250_close(chardev_srv_t *srv)
{
ns8250_t *data = srv_ns8250(srv);
fibril_mutex_lock(&data->mutex);
assert(data->client_connections > 0);
if (!(--data->client_connections))
buf_clear(&data->input_buffer);
fibril_mutex_unlock(&data->mutex);
return EOK;
}
static void ns8250_get_props(ddf_dev_t *dev, unsigned int *baud_rate,
unsigned int *parity, unsigned int *word_length, unsigned int *stop_bits)
{
ns8250_t *data = dev_ns8250(dev);
ns8250_regs_t *regs = data->regs;
fibril_mutex_lock(&data->mutex);
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 "
"length %d, stop bits %d", *baud_rate, *parity, *word_length,
*stop_bits);
}
static errno_t ns8250_set_props(ddf_dev_t *dev, unsigned int baud_rate,
unsigned int parity, unsigned int word_length, unsigned int stop_bits)
{
ddf_msg(LVL_DEBUG, "ns8250_set_props: baud rate %d, parity 0x%x, word "
"length %d, stop bits %d", baud_rate, parity, word_length,
stop_bits);
ns8250_t *data = dev_ns8250(dev);
ns8250_regs_t *regs = data->regs;
errno_t ret;
fibril_mutex_lock(&data->mutex);
ns8250_port_interrupts_disable(regs);
ret = ns8250_port_set_baud_rate(regs, baud_rate);
if (ret == EOK)
ret = ns8250_port_set_com_props(regs, parity, word_length, stop_bits);
ns8250_port_interrupts_enable(regs);
fibril_mutex_unlock(&data->mutex);
return ret;
}
static void ns8250_default_handler(chardev_srv_t *srv, ipc_call_t *call)
{
ns8250_t *ns8250 = srv_ns8250(srv);
sysarg_t method = ipc_get_imethod(call);
errno_t ret;
unsigned int baud_rate, parity, word_length, stop_bits;
switch (method) {
case SERIAL_GET_COM_PROPS:
ns8250_get_props(ns8250->dev, &baud_rate, &parity, &word_length,
&stop_bits);
async_answer_4(call, EOK, baud_rate, parity, word_length,
stop_bits);
break;
case SERIAL_SET_COM_PROPS:
baud_rate = ipc_get_arg1(call);
parity = ipc_get_arg2(call);
word_length = ipc_get_arg3(call);
stop_bits = ipc_get_arg4(call);
ret = ns8250_set_props(ns8250->dev, baud_rate, parity, word_length,
stop_bits);
async_answer_0(call, ret);
break;
default:
async_answer_0(call, ENOTSUP);
}
}
void ns8250_char_conn(ipc_call_t *icall, void *arg)
{
ns8250_t *ns8250 = fun_ns8250((ddf_fun_t *)arg);
chardev_conn(icall, &ns8250->cds);
}
static void ns8250_init(void)
{
ddf_log_init(NAME);
}
int main(int argc, char *argv[])
{
printf(NAME ": HelenOS serial port driver\n");
ns8250_init();
return ddf_driver_main(&ns8250_driver);
}
HelenOS homepage, sources at GitHub