Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/char/ns8250/ns8250.c

    rc7235d40 r4510e06  
    4040#include <stdio.h>
    4141#include <errno.h>
    42 #include <bool.h>
     42#include <stdbool.h>
    4343#include <fibril_synch.h>
    4444#include <stdlib.h>
     
    5151#include <sys/stat.h>
    5252#include <ddi.h>
    53 #include <libarch/ddi.h>
    5453
    5554#include <ddf/driver.h>
     
    5857#include <ops/char_dev.h>
    5958
    60 #include <devman.h>
    6159#include <ns.h>
    62 #include <ipc/devman.h>
    6360#include <ipc/services.h>
    6461#include <ipc/irc.h>
     
    8279/** Interrupt ID Register definition. */
    8380#define NS8250_IID_ACTIVE       (1 << 0)
     81#define NS8250_IID_CAUSE_MASK 0x0e
     82#define NS8250_IID_CAUSE_RXSTATUS 0x06
    8483
    8584/** FIFO Control Register definition. */
     
    126125    | NS8250_MSR_RI | NS8250_MSR_DCD)
    127126
    128 /** Obtain soft-state structure from function node */
    129 #define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data))
    130 
    131 /** Obtain soft-state structure from device node */
    132 #define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data))
    133 
    134127/** The number of bits of one data unit send by the serial port. */
    135128typedef enum {
     
    167160        /** I/O registers **/
    168161        ns8250_regs_t *regs;
    169         /** Is there any client conntected to the device? */
    170         bool client_connected;
     162        /** Are there any clients connected to the device? */
     163        unsigned client_connections;
    171164        /** The irq assigned to this device. */
    172165        int irq;
     
    175168        /** The i/o port used to access the serial ports registers. */
    176169        ioport8_t *port;
    177         /** The buffer for incomming data. */
     170        /** The buffer for incoming data. */
    178171        cyclic_buffer_t input_buffer;
    179172        /** The fibril mutex for synchronizing the access to the device. */
    180173        fibril_mutex_t mutex;
     174        /** Indicates that some data has become available */
     175        fibril_condvar_t input_buffer_available;
    181176        /** True if device is removed. */
    182177        bool removed;
    183178} ns8250_t;
    184179
    185 /** Find out if there is some incomming data available on the serial port.
     180/** Obtain soft-state structure from device node */
     181static ns8250_t *dev_ns8250(ddf_dev_t *dev)
     182{
     183        return ddf_dev_data_get(dev);
     184}
     185
     186/** Obtain soft-state structure from function node */
     187static ns8250_t *fun_ns8250(ddf_fun_t *fun)
     188{
     189        return dev_ns8250(ddf_fun_get_dev(fun));
     190}
     191
     192/** Find out if there is some incoming data available on the serial port.
    186193 *
    187194 * @param port          The base address of the serial port device's ports.
     
    237244static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count)
    238245{
    239         ns8250_t *ns = NS8250(fun);
    240         int ret = EOK;
     246        ns8250_t *ns = fun_ns8250(fun);
     247        int ret = 0;
     248       
     249        if (count == 0) return 0;
    241250       
    242251        fibril_mutex_lock(&ns->mutex);
     252        while (buf_is_empty(&ns->input_buffer))
     253                fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
    243254        while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
    244255                buf[ret] = (char)buf_pop_front(&ns->input_buffer);
     
    271282static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count)
    272283{
    273         ns8250_t *ns = NS8250(fun);
     284        ns8250_t *ns = fun_ns8250(fun);
    274285        size_t idx;
    275286       
     
    309320static void ns8250_dev_cleanup(ns8250_t *ns)
    310321{
    311         if (ns->dev->parent_sess) {
    312                 async_hangup(ns->dev->parent_sess);
    313                 ns->dev->parent_sess = NULL;
    314         }
    315322}
    316323
     
    322329static bool ns8250_pio_enable(ns8250_t *ns)
    323330{
    324         ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ns->dev->name);
     331        ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ddf_dev_get_name(ns->dev));
    325332       
    326333        /* Gain control over port's registers. */
     
    328335            (void **) &ns->port)) {
    329336                ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
    330                     " for device %s.", ns->io_addr, ns->dev->name);
     337                    " for device %s.", ns->io_addr, ddf_dev_get_name(ns->dev));
    331338                return false;
    332339        }
     
    344351static bool ns8250_dev_probe(ns8250_t *ns)
    345352{
    346         ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ns->dev->name);
     353        ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ddf_dev_get_name(ns->dev));
    347354       
    348355        bool res = true;
     
    364371        if (!res) {
    365372                ddf_msg(LVL_DEBUG, "Device %s is not present.",
    366                     ns->dev->name);
     373                    ddf_dev_get_name(ns->dev));
    367374        }
    368375       
     
    377384static int ns8250_dev_initialize(ns8250_t *ns)
    378385{
    379         ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ns->dev->name);
    380        
     386        async_sess_t *parent_sess;
    381387        int ret = EOK;
     388       
     389        ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev));
    382390       
    383391        hw_resource_list_t hw_resources;
     
    385393       
    386394        /* Connect to the parent's driver. */
    387         ns->dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
    388             ns->dev->handle, IPC_FLAG_BLOCKING);
    389         if (!ns->dev->parent_sess) {
     395        parent_sess = ddf_dev_parent_sess_create(ns->dev, EXCHANGE_SERIALIZE);
     396        if (parent_sess == NULL) {
    390397                ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
    391                     "device %s.", ns->dev->name);
     398                    "device %s.", ddf_dev_get_name(ns->dev));
    392399                ret = ENOENT;
    393400                goto failed;
     
    395402       
    396403        /* Get hw resources. */
    397         ret = hw_res_get_resource_list(ns->dev->parent_sess, &hw_resources);
     404        ret = hw_res_get_resource_list(parent_sess, &hw_resources);
    398405        if (ret != EOK) {
    399406                ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
    400                     "%s.", ns->dev->name);
     407                    "%s.", ddf_dev_get_name(ns->dev));
    401408                goto failed;
    402409        }
     
    414421                        irq = true;
    415422                        ddf_msg(LVL_NOTE, "Device %s was asigned irq = 0x%x.",
    416                             ns->dev->name, ns->irq);
     423                            ddf_dev_get_name(ns->dev), ns->irq);
    417424                        break;
    418425                       
     
    421428                        if (res->res.io_range.size < REG_COUNT) {
    422429                                ddf_msg(LVL_ERROR, "I/O range assigned to "
    423                                     "device %s is too small.", ns->dev->name);
     430                                    "device %s is too small.", ddf_dev_get_name(ns->dev));
    424431                                ret = ELIMIT;
    425432                                goto failed;
     
    427434                        ioport = true;
    428435                        ddf_msg(LVL_NOTE, "Device %s was asigned I/O address = "
    429                             "0x%x.", ns->dev->name, ns->io_addr);
     436                            "0x%x.", ddf_dev_get_name(ns->dev), ns->io_addr);
    430437                        break;
    431438                       
     
    437444        if (!irq || !ioport) {
    438445                ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
    439                     ns->dev->name);
     446                    ddf_dev_get_name(ns->dev));
    440447                ret = ENOENT;
    441448                goto failed;
     
    460467{
    461468        /* Interrupt when data received. */
    462         pio_write_8(&regs->ier, NS8250_IER_RXREADY);
     469        pio_write_8(&regs->ier, NS8250_IER_RXREADY | NS8250_IER_RXSTATUS);
    463470        pio_write_8(&regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS
    464471            | NS8250_MCR_OUT2);
     
    499506        async_exchange_end(exch);
    500507
     508        /* Read LSR to clear possible previous LSR interrupt */
     509        pio_read_8(&ns->regs->lsr);
     510
    501511        /* Enable interrupt on the serial port. */
    502512        ns8250_port_interrupts_enable(ns->regs);
     
    602612        *parity = ((val >> NS8250_LCR_PARITY) & 7);
    603613       
     614        /* Silence warnings */
     615        *word_length = 0;
     616
    604617        switch (val & 3) {
    605618        case WORD_LENGTH_5:
     
    695708        /* 8 bits, no parity, two stop bits. */
    696709        ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
    697         /* Enable FIFO, clear them, with 14-byte threshold. */
     710        /*
     711         * Enable FIFO, clear them, with 4-byte threshold for greater
     712         * reliability.
     713         */
    698714        pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE
    699             | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET 
    700             | NS8250_FCR_RXTRIGGERLOW | NS8250_FCR_RXTRIGGERHI);
     715            | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET
     716            | NS8250_FCR_RXTRIGGERLOW);
    701717        /*
    702718         * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
     
    731747        bool cont = true;
    732748       
     749        fibril_mutex_lock(&ns->mutex);
    733750        while (cont) {
    734                 fibril_mutex_lock(&ns->mutex);
    735                
    736751                cont = ns8250_received(regs);
    737752                if (cont) {
    738753                        uint8_t val = ns8250_read_8(regs);
    739754                       
    740                         if (ns->client_connected) {
     755                        if (ns->client_connections > 0) {
     756                                bool buf_was_empty = buf_is_empty(&ns->input_buffer);
    741757                                if (!buf_push_back(&ns->input_buffer, val)) {
    742758                                        ddf_msg(LVL_WARN, "Buffer overflow on "
    743                                             "%s.", ns->dev->name);
     759                                            "%s.", ddf_dev_get_name(ns->dev));
     760                                        break;
    744761                                } else {
    745762                                        ddf_msg(LVL_DEBUG2, "Character %c saved "
    746763                                            "to the buffer of %s.",
    747                                             val, ns->dev->name);
     764                                            val, ddf_dev_get_name(ns->dev));
     765                                        if (buf_was_empty)
     766                                                fibril_condvar_broadcast(&ns->input_buffer_available);
    748767                                }
    749768                        }
    750769                }
    751                
    752                 fibril_mutex_unlock(&ns->mutex);
    753                 fibril_yield();
    754         }
     770        }
     771        fibril_mutex_unlock(&ns->mutex);
     772        fibril_yield();
    755773}
    756774
    757775/** The interrupt handler.
    758776 *
    759  * The serial port is initialized to interrupt when some data come, so the
    760  * interrupt is handled by reading the incomming data.
     777 * The serial port is initialized to interrupt when some data come or line
     778 * status register changes, so the interrupt is handled by reading the incoming
     779 * data and reading the line status register.
    761780 *
    762781 * @param dev           The serial port device.
     
    765784    ipc_call_t *icall)
    766785{
    767         ns8250_read_from_device(NS8250_FROM_DEV(dev));
     786        ns8250_t *ns = dev_ns8250(dev);
     787
     788        uint8_t iir = pio_read_8(&ns->regs->iid);
     789        if ((iir & NS8250_IID_CAUSE_MASK) == NS8250_IID_CAUSE_RXSTATUS) {
     790                uint8_t lsr = pio_read_8(&ns->regs->lsr);
     791                if (lsr & NS8250_LSR_OE) {
     792                        ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
     793                }
     794        }
     795       
     796        ns8250_read_from_device(ns);
    768797}
    769798
     
    801830       
    802831        ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)",
    803             dev->name, (int) dev->handle);
     832            ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
    804833       
    805834        /* Allocate soft-state for the device */
     
    811840       
    812841        fibril_mutex_initialize(&ns->mutex);
     842        fibril_condvar_initialize(&ns->input_buffer_available);
    813843        ns->dev = dev;
    814844       
     
    855885       
    856886        /* Set device operations. */
    857         fun->ops = &ns8250_dev_ops;
     887        ddf_fun_set_ops(fun, &ns8250_dev_ops);
    858888        rc = ddf_fun_bind(fun);
    859889        if (rc != EOK) {
     
    867897       
    868898        ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
    869             dev->name);
     899            ddf_dev_get_name(dev));
    870900       
    871901        return EOK;
     
    880910static int ns8250_dev_remove(ddf_dev_t *dev)
    881911{
    882         ns8250_t *ns = NS8250_FROM_DEV(dev);
     912        ns8250_t *ns = dev_ns8250(dev);
    883913        int rc;
    884914       
    885915        fibril_mutex_lock(&ns->mutex);
    886         if (ns->client_connected) {
     916                if (ns->client_connections > 0) {
    887917                fibril_mutex_unlock(&ns->mutex);
    888918                return EBUSY;
     
    914944static int ns8250_open(ddf_fun_t *fun)
    915945{
    916         ns8250_t *ns = NS8250(fun);
     946        ns8250_t *ns = fun_ns8250(fun);
    917947        int res;
    918948       
    919949        fibril_mutex_lock(&ns->mutex);
    920         if (ns->client_connected) {
    921                 res = ELIMIT;
    922         } else if (ns->removed) {
     950        if (ns->removed) {
    923951                res = ENXIO;
    924952        } else {
    925953                res = EOK;
    926                 ns->client_connected = true;
     954                ns->client_connections++;
    927955        }
    928956        fibril_mutex_unlock(&ns->mutex);
     
    940968static void ns8250_close(ddf_fun_t *fun)
    941969{
    942         ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
     970        ns8250_t *data = fun_ns8250(fun);
    943971       
    944972        fibril_mutex_lock(&data->mutex);
    945973       
    946         assert(data->client_connected);
    947        
    948         data->client_connected = false;
    949         buf_clear(&data->input_buffer);
     974        assert(data->client_connections > 0);
     975       
     976        if (!(--data->client_connections))
     977                buf_clear(&data->input_buffer);
    950978       
    951979        fibril_mutex_unlock(&data->mutex);
     
    965993    unsigned int *word_length, unsigned int* stop_bits)
    966994{
    967         ns8250_t *data = (ns8250_t *) dev->driver_data;
     995        ns8250_t *data = dev_ns8250(dev);
    968996        ns8250_regs_t *regs = data->regs;
    969997       
     
    9961024            stop_bits);
    9971025       
    998         ns8250_t *data = (ns8250_t *) dev->driver_data;
     1026        ns8250_t *data = dev_ns8250(dev);
    9991027        ns8250_regs_t *regs = data->regs;
    10001028        int ret;
     
    10251053        switch (method) {
    10261054        case SERIAL_GET_COM_PROPS:
    1027                 ns8250_get_props(fun->dev, &baud_rate, &parity, &word_length,
     1055                ns8250_get_props(ddf_fun_get_dev(fun), &baud_rate, &parity, &word_length,
    10281056                    &stop_bits);
    10291057                async_answer_4(callid, EOK, baud_rate, parity, word_length,
     
    10361064                word_length = IPC_GET_ARG3(*call);
    10371065                stop_bits = IPC_GET_ARG4(*call);
    1038                 ret = ns8250_set_props(fun->dev, baud_rate, parity, word_length,
     1066                ret = ns8250_set_props(ddf_fun_get_dev(fun), baud_rate, parity, word_length,
    10391067                    stop_bits);
    10401068                async_answer_0(callid, ret);
     
    10531081static void ns8250_init(void)
    10541082{
    1055         ddf_log_init(NAME, LVL_ERROR);
     1083        ddf_log_init(NAME);
    10561084       
    10571085        ns8250_dev_ops.open = &ns8250_open;
Note: See TracChangeset for help on using the changeset viewer.