Changeset beb9336 in mainline for uspace/drv/char/ns8250/ns8250.c


Ignore:
Timestamp:
2012-08-24T14:07:52Z (12 years ago)
Author:
Frantisek Princ <frantisek.princ@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
041ab64
Parents:
bd29f9c9 (diff), db81577 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge with mainline

File:
1 edited

Legend:

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

    rbd29f9c9 rbeb9336  
    5858#include <ops/char_dev.h>
    5959
    60 #include <devman.h>
    6160#include <ns.h>
    62 #include <ipc/devman.h>
    6361#include <ipc/services.h>
    6462#include <ipc/irc.h>
     
    8280/** Interrupt ID Register definition. */
    8381#define NS8250_IID_ACTIVE       (1 << 0)
     82#define NS8250_IID_CAUSE_MASK 0x0e
     83#define NS8250_IID_CAUSE_RXSTATUS 0x06
    8484
    8585/** FIFO Control Register definition. */
     
    125125#define NS8250_MSR_SIGNALS      (NS8250_MSR_CTS | NS8250_MSR_DSR \
    126126    | NS8250_MSR_RI | NS8250_MSR_DCD)
    127 
    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))
    133127
    134128/** The number of bits of one data unit send by the serial port. */
     
    179173        /** The fibril mutex for synchronizing the access to the device. */
    180174        fibril_mutex_t mutex;
     175        /** Indicates that some data has become available */
     176        fibril_condvar_t input_buffer_available;
    181177        /** True if device is removed. */
    182178        bool removed;
    183179} ns8250_t;
    184180
     181/** Obtain soft-state structure from device node */
     182static ns8250_t *dev_ns8250(ddf_dev_t *dev)
     183{
     184        return ddf_dev_data_get(dev);
     185}
     186
     187/** Obtain soft-state structure from function node */
     188static ns8250_t *fun_ns8250(ddf_fun_t *fun)
     189{
     190        return dev_ns8250(ddf_fun_get_dev(fun));
     191}
     192
    185193/** Find out if there is some incomming data available on the serial port.
    186194 *
     
    237245static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count)
    238246{
    239         ns8250_t *ns = NS8250(fun);
    240         int ret = EOK;
     247        ns8250_t *ns = fun_ns8250(fun);
     248        int ret = 0;
     249       
     250        if (count == 0) return 0;
    241251       
    242252        fibril_mutex_lock(&ns->mutex);
     253        while (buf_is_empty(&ns->input_buffer))
     254                fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
    243255        while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
    244256                buf[ret] = (char)buf_pop_front(&ns->input_buffer);
     
    271283static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count)
    272284{
    273         ns8250_t *ns = NS8250(fun);
     285        ns8250_t *ns = fun_ns8250(fun);
    274286        size_t idx;
    275287       
     
    309321static void ns8250_dev_cleanup(ns8250_t *ns)
    310322{
    311         if (ns->dev->parent_sess) {
    312                 async_hangup(ns->dev->parent_sess);
    313                 ns->dev->parent_sess = NULL;
    314         }
    315323}
    316324
     
    322330static bool ns8250_pio_enable(ns8250_t *ns)
    323331{
    324         ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ns->dev->name);
     332        ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ddf_dev_get_name(ns->dev));
    325333       
    326334        /* Gain control over port's registers. */
     
    328336            (void **) &ns->port)) {
    329337                ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
    330                     " for device %s.", ns->io_addr, ns->dev->name);
     338                    " for device %s.", ns->io_addr, ddf_dev_get_name(ns->dev));
    331339                return false;
    332340        }
     
    344352static bool ns8250_dev_probe(ns8250_t *ns)
    345353{
    346         ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ns->dev->name);
     354        ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ddf_dev_get_name(ns->dev));
    347355       
    348356        bool res = true;
     
    364372        if (!res) {
    365373                ddf_msg(LVL_DEBUG, "Device %s is not present.",
    366                     ns->dev->name);
     374                    ddf_dev_get_name(ns->dev));
    367375        }
    368376       
     
    377385static int ns8250_dev_initialize(ns8250_t *ns)
    378386{
    379         ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ns->dev->name);
    380        
     387        async_sess_t *parent_sess;
    381388        int ret = EOK;
     389       
     390        ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev));
    382391       
    383392        hw_resource_list_t hw_resources;
     
    385394       
    386395        /* 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) {
     396        parent_sess = ddf_dev_parent_sess_create(ns->dev, EXCHANGE_SERIALIZE);
     397        if (parent_sess == NULL) {
    390398                ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
    391                     "device %s.", ns->dev->name);
     399                    "device %s.", ddf_dev_get_name(ns->dev));
    392400                ret = ENOENT;
    393401                goto failed;
     
    395403       
    396404        /* Get hw resources. */
    397         ret = hw_res_get_resource_list(ns->dev->parent_sess, &hw_resources);
     405        ret = hw_res_get_resource_list(parent_sess, &hw_resources);
    398406        if (ret != EOK) {
    399407                ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
    400                     "%s.", ns->dev->name);
     408                    "%s.", ddf_dev_get_name(ns->dev));
    401409                goto failed;
    402410        }
     
    414422                        irq = true;
    415423                        ddf_msg(LVL_NOTE, "Device %s was asigned irq = 0x%x.",
    416                             ns->dev->name, ns->irq);
     424                            ddf_dev_get_name(ns->dev), ns->irq);
    417425                        break;
    418426                       
     
    421429                        if (res->res.io_range.size < REG_COUNT) {
    422430                                ddf_msg(LVL_ERROR, "I/O range assigned to "
    423                                     "device %s is too small.", ns->dev->name);
     431                                    "device %s is too small.", ddf_dev_get_name(ns->dev));
    424432                                ret = ELIMIT;
    425433                                goto failed;
     
    427435                        ioport = true;
    428436                        ddf_msg(LVL_NOTE, "Device %s was asigned I/O address = "
    429                             "0x%x.", ns->dev->name, ns->io_addr);
     437                            "0x%x.", ddf_dev_get_name(ns->dev), ns->io_addr);
    430438                        break;
    431439                       
     
    437445        if (!irq || !ioport) {
    438446                ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
    439                     ns->dev->name);
     447                    ddf_dev_get_name(ns->dev));
    440448                ret = ENOENT;
    441449                goto failed;
     
    460468{
    461469        /* Interrupt when data received. */
    462         pio_write_8(&regs->ier, NS8250_IER_RXREADY);
     470        pio_write_8(&regs->ier, NS8250_IER_RXREADY | NS8250_IER_RXSTATUS);
    463471        pio_write_8(&regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS
    464472            | NS8250_MCR_OUT2);
     
    499507        async_exchange_end(exch);
    500508
     509        /* Read LSR to clear possible previous LSR interrupt */
     510        pio_read_8(&ns->regs->lsr);
     511
    501512        /* Enable interrupt on the serial port. */
    502513        ns8250_port_interrupts_enable(ns->regs);
     
    602613        *parity = ((val >> NS8250_LCR_PARITY) & 7);
    603614       
     615        /* Silence warnings */
     616        *word_length = 0;
     617
    604618        switch (val & 3) {
    605619        case WORD_LENGTH_5:
     
    695709        /* 8 bits, no parity, two stop bits. */
    696710        ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
    697         /* Enable FIFO, clear them, with 14-byte threshold. */
     711        /*
     712         * Enable FIFO, clear them, with 4-byte threshold for greater
     713         * reliability.
     714         */
    698715        pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE
    699             | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET 
    700             | NS8250_FCR_RXTRIGGERLOW | NS8250_FCR_RXTRIGGERHI);
     716            | NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET
     717            | NS8250_FCR_RXTRIGGERLOW);
    701718        /*
    702719         * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
     
    731748        bool cont = true;
    732749       
     750        fibril_mutex_lock(&ns->mutex);
    733751        while (cont) {
    734                 fibril_mutex_lock(&ns->mutex);
    735                
    736752                cont = ns8250_received(regs);
    737753                if (cont) {
     
    739755                       
    740756                        if (ns->client_connected) {
     757                                bool buf_was_empty = buf_is_empty(&ns->input_buffer);
    741758                                if (!buf_push_back(&ns->input_buffer, val)) {
    742759                                        ddf_msg(LVL_WARN, "Buffer overflow on "
    743                                             "%s.", ns->dev->name);
     760                                            "%s.", ddf_dev_get_name(ns->dev));
     761                                        break;
    744762                                } else {
    745763                                        ddf_msg(LVL_DEBUG2, "Character %c saved "
    746764                                            "to the buffer of %s.",
    747                                             val, ns->dev->name);
     765                                            val, ddf_dev_get_name(ns->dev));
     766                                        if (buf_was_empty)
     767                                                fibril_condvar_broadcast(&ns->input_buffer_available);
    748768                                }
    749769                        }
    750770                }
    751                
    752                 fibril_mutex_unlock(&ns->mutex);
    753                 fibril_yield();
    754         }
     771        }
     772        fibril_mutex_unlock(&ns->mutex);
     773        fibril_yield();
    755774}
    756775
    757776/** The interrupt handler.
    758777 *
    759  * The serial port is initialized to interrupt when some data come, so the
    760  * interrupt is handled by reading the incomming data.
     778 * The serial port is initialized to interrupt when some data come or line
     779 * status register changes, so the interrupt is handled by reading the incoming
     780 * data and reading the line status register.
    761781 *
    762782 * @param dev           The serial port device.
     
    765785    ipc_call_t *icall)
    766786{
    767         ns8250_read_from_device(NS8250_FROM_DEV(dev));
     787        ns8250_t *ns = dev_ns8250(dev);
     788
     789        uint8_t iir = pio_read_8(&ns->regs->iid);
     790        if ((iir & NS8250_IID_CAUSE_MASK) == NS8250_IID_CAUSE_RXSTATUS) {
     791                uint8_t lsr = pio_read_8(&ns->regs->lsr);
     792                if (lsr & NS8250_LSR_OE) {
     793                        ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
     794                }
     795        }
     796       
     797        ns8250_read_from_device(ns);
    768798}
    769799
     
    801831       
    802832        ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)",
    803             dev->name, (int) dev->handle);
     833            ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
    804834       
    805835        /* Allocate soft-state for the device */
     
    811841       
    812842        fibril_mutex_initialize(&ns->mutex);
     843        fibril_condvar_initialize(&ns->input_buffer_available);
    813844        ns->dev = dev;
    814845       
     
    855886       
    856887        /* Set device operations. */
    857         fun->ops = &ns8250_dev_ops;
     888        ddf_fun_set_ops(fun, &ns8250_dev_ops);
    858889        rc = ddf_fun_bind(fun);
    859890        if (rc != EOK) {
     
    867898       
    868899        ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
    869             dev->name);
     900            ddf_dev_get_name(dev));
    870901       
    871902        return EOK;
     
    880911static int ns8250_dev_remove(ddf_dev_t *dev)
    881912{
    882         ns8250_t *ns = NS8250_FROM_DEV(dev);
     913        ns8250_t *ns = dev_ns8250(dev);
    883914        int rc;
    884915       
     
    914945static int ns8250_open(ddf_fun_t *fun)
    915946{
    916         ns8250_t *ns = NS8250(fun);
     947        ns8250_t *ns = fun_ns8250(fun);
    917948        int res;
    918949       
     
    940971static void ns8250_close(ddf_fun_t *fun)
    941972{
    942         ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
     973        ns8250_t *data = fun_ns8250(fun);
    943974       
    944975        fibril_mutex_lock(&data->mutex);
     
    965996    unsigned int *word_length, unsigned int* stop_bits)
    966997{
    967         ns8250_t *data = (ns8250_t *) dev->driver_data;
     998        ns8250_t *data = dev_ns8250(dev);
    968999        ns8250_regs_t *regs = data->regs;
    9691000       
     
    9961027            stop_bits);
    9971028       
    998         ns8250_t *data = (ns8250_t *) dev->driver_data;
     1029        ns8250_t *data = dev_ns8250(dev);
    9991030        ns8250_regs_t *regs = data->regs;
    10001031        int ret;
     
    10251056        switch (method) {
    10261057        case SERIAL_GET_COM_PROPS:
    1027                 ns8250_get_props(fun->dev, &baud_rate, &parity, &word_length,
     1058                ns8250_get_props(ddf_fun_get_dev(fun), &baud_rate, &parity, &word_length,
    10281059                    &stop_bits);
    10291060                async_answer_4(callid, EOK, baud_rate, parity, word_length,
     
    10361067                word_length = IPC_GET_ARG3(*call);
    10371068                stop_bits = IPC_GET_ARG4(*call);
    1038                 ret = ns8250_set_props(fun->dev, baud_rate, parity, word_length,
     1069                ret = ns8250_set_props(ddf_fun_get_dev(fun), baud_rate, parity, word_length,
    10391070                    stop_bits);
    10401071                async_answer_0(callid, ret);
     
    10531084static void ns8250_init(void)
    10541085{
    1055         ddf_log_init(NAME, LVL_ERROR);
     1086        ddf_log_init(NAME, LVL_WARN);
    10561087       
    10571088        ns8250_dev_ops.open = &ns8250_open;
Note: See TracChangeset for help on using the changeset viewer.