Changeset 68414f4a in mainline for uspace/drv/ns8250/ns8250.c


Ignore:
Timestamp:
2011-02-13T20:03:45Z (14 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bab6388
Parents:
8b1e15ac
Message:

Refactor drivers

  • Rename soft-state structures to have the simplest names
  • Use soft-state structures as a starting point instead of DDF device or function nodes
  • Convert to standard naming scheme
File:
1 edited

Legend:

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

    r8b1e15ac r68414f4a  
    1 /*                       
     1/*
    22 * Copyright (c) 2010 Lenka Trochtova
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    6869#define DLAB_MASK (1 << 7)
    6970
     71/** Obtain soft-state structure from function node */
     72#define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data))
     73
     74/** Obtain soft-state structure from device node */
     75#define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data))
     76
    7077/** The number of bits of one data unit send by the serial port. */
    7178typedef enum {
     
    8592
    8693/** The driver data for the serial port devices. */
    87 typedef struct ns8250_dev_data {
     94typedef struct ns8250 {
     95        /** DDF device node */
     96        device_t *dev;
     97        /** DDF function node */
     98        function_t *fun;
    8899        /** Is there any client conntected to the device? */
    89100        bool client_connected;
     
    98109        /** The fibril mutex for synchronizing the access to the device. */
    99110        fibril_mutex_t mutex;
    100 } ns8250_dev_data_t;
    101 
    102 /** Create driver data for a device.
    103  *
    104  * @return              The driver data.
    105  */
    106 static ns8250_dev_data_t *create_ns8250_dev_data(void)
    107 {
    108         ns8250_dev_data_t *data;
    109        
    110         data = (ns8250_dev_data_t *) malloc(sizeof(ns8250_dev_data_t));
    111         if (NULL != data) {
    112                 memset(data, 0, sizeof(ns8250_dev_data_t));
    113                 fibril_mutex_initialize(&data->mutex);
    114         }
    115         return data;
    116 }
    117 
    118 /** Delete driver data.
    119  *
    120  * @param data          The driver data structure.
    121  */
    122 static void delete_ns8250_dev_data(ns8250_dev_data_t *data)
    123 {
    124         if (data != NULL)
    125                 free(data);
     111} ns8250_t;
     112
     113/** Create per-device soft-state structure.
     114 *
     115 * @return      Pointer to soft-state structure.
     116 */
     117static ns8250_t *ns8250_new(void)
     118{
     119        ns8250_t *ns;
     120       
     121        ns = (ns8250_t *) calloc(1, sizeof(ns8250_t));
     122        if (ns == NULL)
     123                return NULL;
     124       
     125        fibril_mutex_initialize(&ns->mutex);
     126        return ns;
     127}
     128
     129/** Delete soft-state structure.
     130 *
     131 * @param ns    The driver data structure.
     132 */
     133static void ns8250_delete(ns8250_t *ns)
     134{
     135        free(ns);
    126136}
    127137
     
    171181/** Read data from the serial port device.
    172182 *
    173  * @param dev           The serial port device.
     183 * @param fun           The serial port function
    174184 * @param buf           The ouput buffer for read data.
    175185 * @param count         The number of bytes to be read.
     
    180190static int ns8250_read(function_t *fun, char *buf, size_t count)
    181191{
     192        ns8250_t *ns = NS8250(fun);
    182193        int ret = EOK;
    183         ns8250_dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;
    184        
    185         fibril_mutex_lock(&data->mutex);
    186         while (!buf_is_empty(&data->input_buffer) && (size_t)ret < count) {
    187                 buf[ret] = (char)buf_pop_front(&data->input_buffer);
     194       
     195        fibril_mutex_lock(&ns->mutex);
     196        while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
     197                buf[ret] = (char)buf_pop_front(&ns->input_buffer);
    188198                ret++;
    189199        }
    190         fibril_mutex_unlock(&data->mutex);
     200        fibril_mutex_unlock(&ns->mutex);
    191201       
    192202        return ret;
     
    195205/** Write a character to the serial port.
    196206 *
    197  * @param data          The serial port device's driver data.
    198  * @param c             The character to be written.
    199  */
    200 static inline void ns8250_putchar(ns8250_dev_data_t *data, uint8_t c)
    201 {
    202         fibril_mutex_lock(&data->mutex);
    203         ns8250_write_8(data->port, c);
    204         fibril_mutex_unlock(&data->mutex);
     207 * @param ns            Serial port device
     208 * @param c             The character to be written
     209 */
     210static inline void ns8250_putchar(ns8250_t *ns, uint8_t c)
     211{
     212        fibril_mutex_lock(&ns->mutex);
     213        ns8250_write_8(ns->port, c);
     214        fibril_mutex_unlock(&ns->mutex);
    205215}
    206216
    207217/** Write data to the serial port.
    208218 *
    209  * @param dev           The serial port device.
    210  * @param buf           The data to be written.
    211  * @param count         The number of bytes to be written.
    212  * @return              Zero on success.
     219 * @param fun           The serial port function
     220 * @param buf           The data to be written
     221 * @param count         The number of bytes to be written
     222 * @return              Zero on success
    213223 */
    214224static int ns8250_write(function_t *fun, char *buf, size_t count)
    215225{
    216         ns8250_dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;
     226        ns8250_t *ns = NS8250(fun);
    217227        size_t idx;
    218228       
    219229        for (idx = 0; idx < count; idx++)
    220                 ns8250_putchar(data, (uint8_t) buf[idx]);
     230                ns8250_putchar(ns, (uint8_t) buf[idx]);
    221231       
    222232        return 0;
     
    244254};
    245255
    246 /** Clean up the serial port device structure.
    247  *
    248  * @param dev           The device structure.
    249  */
    250 static void ns8250_dev_cleanup(device_t *dev)
    251 {
    252         if (dev->driver_data != NULL) {
    253                 delete_ns8250_dev_data((ns8250_dev_data_t*) dev->driver_data);
    254                 dev->driver_data = NULL;
    255         }
    256        
    257         if (dev->parent_phone > 0) {
    258                 async_hangup(dev->parent_phone);
    259                 dev->parent_phone = 0;
     256/** Clean up the serial port soft-state
     257 *
     258 * @param ns            Serial port device
     259 */
     260static void ns8250_dev_cleanup(ns8250_t *ns)
     261{
     262        if (ns->dev->parent_phone > 0) {
     263                async_hangup(ns->dev->parent_phone);
     264                ns->dev->parent_phone = 0;
    260265        }
    261266}
     
    263268/** Enable the i/o ports of the device.
    264269 *
    265  * @param dev           The serial port device.
    266  * @return              True on success, false otherwise.
    267  */
    268 static bool ns8250_pio_enable(device_t *dev)
    269 {
    270         printf(NAME ": ns8250_pio_enable %s\n", dev->name);
    271        
    272         ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;
     270 * @param ns            Serial port device
     271 * @return              True on success, false otherwise
     272 */
     273static bool ns8250_pio_enable(ns8250_t *ns)
     274{
     275        printf(NAME ": ns8250_pio_enable %s\n", ns->dev->name);
    273276       
    274277        /* Gain control over port's registers. */
    275         if (pio_enable((void *)(uintptr_t) data->io_addr, REG_COUNT,
    276             (void **) &data->port)) {
     278        if (pio_enable((void *)(uintptr_t) ns->io_addr, REG_COUNT,
     279            (void **) &ns->port)) {
    277280                printf(NAME ": error - cannot gain the port %#" PRIx32 " for device "
    278                     "%s.\n", data->io_addr, dev->name);
     281                    "%s.\n", ns->io_addr, ns->dev->name);
    279282                return false;
    280283        }
     
    285288/** Probe the serial port device for its presence.
    286289 *
    287  * @param dev           The serial port device.
    288  * @return              True if the device is present, false otherwise.
    289  */
    290 static bool ns8250_dev_probe(device_t *dev)
    291 {
    292         printf(NAME ": ns8250_dev_probe %s\n", dev->name);
    293        
    294         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
    295         ioport8_t *port_addr = data->port;
     290 * @param ns            Serial port device
     291 * @return              True if the device is present, false otherwise
     292 */
     293static bool ns8250_dev_probe(ns8250_t *ns)
     294{
     295        printf(NAME ": ns8250_dev_probe %s\n", ns->dev->name);
     296       
     297        ioport8_t *port_addr = ns->port;
    296298        bool res = true;
    297299        uint8_t olddata;
     
    310312       
    311313        if (!res)
    312                 printf(NAME ": device %s is not present.\n", dev->name);
     314                printf(NAME ": device %s is not present.\n", ns->dev->name);
    313315       
    314316        return res;
     
    317319/** Initialize serial port device.
    318320 *
    319  * @param dev           The serial port device.
    320  * @return              Zero on success, negative error number otherwise.
    321  */
    322 static int ns8250_dev_initialize(device_t *dev)
    323 {
    324         printf(NAME ": ns8250_dev_initialize %s\n", dev->name);
     321 * @param ns            Serial port device
     322 * @return              Zero on success, negative error number otherwise
     323 */
     324static int ns8250_dev_initialize(ns8250_t *ns)
     325{
     326        printf(NAME ": ns8250_dev_initialize %s\n", ns->dev->name);
    325327       
    326328        int ret = EOK;
     
    329331        memset(&hw_resources, 0, sizeof(hw_resource_list_t));
    330332       
    331         /* Allocate driver data for the device. */
    332         ns8250_dev_data_t *data = create_ns8250_dev_data();
    333         if (data == NULL)
    334                 return ENOMEM;
    335         dev->driver_data = data;
    336        
    337333        /* Connect to the parent's driver. */
    338         dev->parent_phone = devman_parent_device_connect(dev->handle,
     334        ns->dev->parent_phone = devman_parent_device_connect(ns->dev->handle,
    339335            IPC_FLAG_BLOCKING);
    340         if (dev->parent_phone < 0) {
     336        if (ns->dev->parent_phone < 0) {
    341337                printf(NAME ": failed to connect to the parent driver of the "
    342                     "device %s.\n", dev->name);
    343                 ret = dev->parent_phone;
     338                    "device %s.\n", ns->dev->name);
     339                ret = ns->dev->parent_phone;
    344340                goto failed;
    345341        }
    346342       
    347343        /* Get hw resources. */
    348         ret = hw_res_get_resource_list(dev->parent_phone, &hw_resources);
     344        ret = hw_res_get_resource_list(ns->dev->parent_phone, &hw_resources);
    349345        if (ret != EOK) {
    350346                printf(NAME ": failed to get hw resources for the device "
    351                     "%s.\n", dev->name);
     347                    "%s.\n", ns->dev->name);
    352348                goto failed;
    353349        }
     
    362358                switch (res->type) {
    363359                case INTERRUPT:
    364                         data->irq = res->res.interrupt.irq;
     360                        ns->irq = res->res.interrupt.irq;
    365361                        irq = true;
    366362                        printf(NAME ": the %s device was asigned irq = 0x%x.\n",
    367                             dev->name, data->irq);
     363                            ns->dev->name, ns->irq);
    368364                        break;
    369365                       
    370366                case IO_RANGE:
    371                         data->io_addr = res->res.io_range.address;
     367                        ns->io_addr = res->res.io_range.address;
    372368                        if (res->res.io_range.size < REG_COUNT) {
    373369                                printf(NAME ": i/o range assigned to the device "
    374                                     "%s is too small.\n", dev->name);
     370                                    "%s is too small.\n", ns->dev->name);
    375371                                ret = ELIMIT;
    376372                                goto failed;
     
    378374                        ioport = true;
    379375                        printf(NAME ": the %s device was asigned i/o address = "
    380                             "0x%x.\n", dev->name, data->io_addr);
     376                            "0x%x.\n", ns->dev->name, ns->io_addr);
    381377                        break;
    382378                       
     
    388384        if (!irq || !ioport) {
    389385                printf(NAME ": missing hw resource(s) for the device %s.\n",
    390                     dev->name);
     386                    ns->dev->name);
    391387                ret = ENOENT;
    392388                goto failed;
     
    397393       
    398394failed:
    399         ns8250_dev_cleanup(dev);
     395        ns8250_dev_cleanup(ns);
    400396        hw_res_clean_resource_list(&hw_resources);
    401397        return ret;
     
    404400/** Enable interrupts on the serial port device.
    405401 *
    406  * Interrupt when data is received.
     402 * Interrupt when data is received
    407403 *
    408404 * @param port          The base address of the serial port device's ports.
     
    416412/** Disable interrupts on the serial port device.
    417413 *
    418  * @param port          The base address of the serial port device's ports.
     414 * @param port          The base address of the serial port device's ports
    419415 */
    420416static inline void ns8250_port_interrupts_disable(ioport8_t *port)
     
    425421/** Enable interrupts for the serial port device.
    426422 *
    427  * @param dev           The device.
    428  * @return              Zero on success, negative error number otherwise.
    429  */
    430 static int ns8250_interrupt_enable(device_t *dev)
    431 {
    432         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
    433        
     423 * @param ns            Serial port device
     424 * @return              Zero on success, negative error number otherwise
     425 */
     426static int ns8250_interrupt_enable(ns8250_t *ns)
     427{
    434428        /* Enable interrupt on the serial port. */
    435         ns8250_port_interrupts_enable(data->port);
     429        ns8250_port_interrupts_enable(ns->port);
    436430       
    437431        return EOK;
     
    618612 * Set the default parameters of the serial communication.
    619613 *
    620  * @param dev           The serial port device.
    621  */
    622 static void ns8250_initialize_port(device_t *dev)
    623 {
    624         ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;
    625         ioport8_t *port = data->port;
     614 * @param ns            Serial port device
     615 */
     616static void ns8250_initialize_port(ns8250_t *ns)
     617{
     618        ioport8_t *port = ns->port;
    626619       
    627620        /* Disable interrupts. */
     
    643636 * buffer.
    644637 *
    645  * @param dev           The serial port device.
    646  */
    647 static void ns8250_read_from_device(device_t *dev)
    648 {
    649         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
    650         ioport8_t *port = data->port;
     638 * @param ns            Serial port device
     639 */
     640static void ns8250_read_from_device(ns8250_t *ns)
     641{
     642        ioport8_t *port = ns->port;
    651643        bool cont = true;
    652644       
    653645        while (cont) {
    654                 fibril_mutex_lock(&data->mutex);
     646                fibril_mutex_lock(&ns->mutex);
    655647               
    656648                cont = ns8250_received(port);
     
    658650                        uint8_t val = ns8250_read_8(port);
    659651                       
    660                         if (data->client_connected) {
    661                                 if (!buf_push_back(&data->input_buffer, val)) {
     652                        if (ns->client_connected) {
     653                                if (!buf_push_back(&ns->input_buffer, val)) {
    662654                                        printf(NAME ": buffer overflow on "
    663                                             "%s.\n", dev->name);
     655                                            "%s.\n", ns->dev->name);
    664656                                } else {
    665657                                        printf(NAME ": the character %c saved "
    666658                                            "to the buffer of %s.\n",
    667                                             val, dev->name);
     659                                            val, ns->dev->name);
    668660                                }
    669661                        }
    670662                }
    671663               
    672                 fibril_mutex_unlock(&data->mutex);
     664                fibril_mutex_unlock(&ns->mutex);
    673665                fibril_yield();
    674666        }
     
    685677    ipc_call_t *icall)
    686678{
    687         ns8250_read_from_device(dev);
     679        ns8250_read_from_device(NS8250_FROM_DEV(dev));
    688680}
    689681
    690682/** Register the interrupt handler for the device.
    691683 *
     684 * @param ns            Serial port device
     685 */
     686static inline int ns8250_register_interrupt_handler(ns8250_t *ns)
     687{
     688        return register_interrupt_handler(ns->dev, ns->irq,
     689            ns8250_interrupt_handler, NULL);
     690}
     691
     692/** Unregister the interrupt handler for the device.
     693 *
     694 * @param ns            Serial port device
     695 */
     696static inline int ns8250_unregister_interrupt_handler(ns8250_t *ns)
     697{
     698        return unregister_interrupt_handler(ns->dev, ns->irq);
     699}
     700
     701/** The add_device callback method of the serial port driver.
     702 *
     703 * Probe and initialize the newly added device.
     704 *
    692705 * @param dev           The serial port device.
    693706 */
    694 static inline int ns8250_register_interrupt_handler(device_t *dev)
    695 {
    696         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
    697        
    698         return register_interrupt_handler(dev, data->irq,
    699             ns8250_interrupt_handler, NULL);
    700 }
    701 
    702 /** Unregister the interrupt handler for the device.
    703  *
    704  * @param dev           The serial port device.
    705  */
    706 static inline int ns8250_unregister_interrupt_handler(device_t *dev)
    707 {
    708         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
    709        
    710         return unregister_interrupt_handler(dev, data->irq);
    711 }
    712 
    713 /** The add_device callback method of the serial port driver.
    714  *
    715  * Probe and initialize the newly added device.
    716  *
    717  * @param dev           The serial port device.
    718  */
    719707static int ns8250_add_device(device_t *dev)
    720708{
    721         function_t *fun;
    722 
     709        ns8250_t *ns = NULL;
     710        function_t *fun = NULL;
     711        bool need_cleanup = false;
     712        int rc;
     713       
    723714        printf(NAME ": ns8250_add_device %s (handle = %d)\n",
    724715            dev->name, (int) dev->handle);
    725716       
    726         int res = ns8250_dev_initialize(dev);
    727         if (res != EOK)
    728                 return res;
    729        
    730         if (!ns8250_pio_enable(dev)) {
    731                 ns8250_dev_cleanup(dev);
    732                 return EADDRNOTAVAIL;
     717        /* Allocate soft-state for the device */
     718        ns = ns8250_new();
     719        if (ns == NULL) {
     720                rc = ENOMEM;
     721                goto fail;
     722        }
     723       
     724        ns->dev = dev;
     725        dev->driver_data = ns;
     726       
     727        rc = ns8250_dev_initialize(ns);
     728        if (rc != EOK)
     729                goto fail;
     730       
     731        need_cleanup = true;
     732       
     733        if (!ns8250_pio_enable(ns)) {
     734                rc = EADDRNOTAVAIL;
     735                goto fail;
    733736        }
    734737       
    735738        /* Find out whether the device is present. */
    736         if (!ns8250_dev_probe(dev)) {
    737                 ns8250_dev_cleanup(dev);
    738                 return ENOENT;
     739        if (!ns8250_dev_probe(ns)) {
     740                rc = ENOENT;
     741                goto fail;
    739742        }
    740743       
    741744        /* Serial port initialization (baud rate etc.). */
    742         ns8250_initialize_port(dev);
     745        ns8250_initialize_port(ns);
    743746       
    744747        /* Register interrupt handler. */
    745         if (ns8250_register_interrupt_handler(dev) != EOK) {
     748        if (ns8250_register_interrupt_handler(ns) != EOK) {
    746749                printf(NAME ": failed to register interrupt handler.\n");
    747                 ns8250_dev_cleanup(dev);
    748                 return res;
     750                rc = EADDRNOTAVAIL;
     751                goto fail;
    749752        }
    750753       
    751754        /* Enable interrupt. */
    752         res = ns8250_interrupt_enable(dev);
    753         if (res != EOK) {
     755        rc = ns8250_interrupt_enable(ns);
     756        if (rc != EOK) {
    754757                printf(NAME ": failed to enable the interrupt. Error code = "
    755                     "%d.\n", res);
    756                 ns8250_dev_cleanup(dev);
    757                 ns8250_unregister_interrupt_handler(dev);
    758                 return res;
    759         }
    760 
     758                    "%d.\n", rc);
     759                goto fail;
     760        }
     761       
    761762        fun = create_function();
    762763        fun->ftype = fun_exposed;
     
    766767        fun->ops = &ns8250_dev_ops;
    767768        register_function(fun, dev);
     769        ns->fun = fun;
    768770       
    769771        add_function_to_class(fun, "serial");
     
    773775       
    774776        return EOK;
     777fail:
     778        if (need_cleanup)
     779                ns8250_dev_cleanup(ns);
     780        if (ns != NULL)
     781                ns8250_delete(ns);
     782        return rc;
    775783}
    776784
     
    784792static int ns8250_open(function_t *fun)
    785793{
    786         ns8250_dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;
     794        ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
    787795        int res;
    788796       
     
    808816static void ns8250_close(function_t *fun)
    809817{
    810         ns8250_dev_data_t *data = (ns8250_dev_data_t *) fun->dev->driver_data;
     818        ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
    811819       
    812820        fibril_mutex_lock(&data->mutex);
     
    833841    unsigned int *word_length, unsigned int* stop_bits)
    834842{
    835         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
     843        ns8250_t *data = (ns8250_t *) dev->driver_data;
    836844        ioport8_t *port = data->port;
    837845       
     
    864872            stop_bits);
    865873       
    866         ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
     874        ns8250_t *data = (ns8250_t *) dev->driver_data;
    867875        ioport8_t *port = data->port;
    868876        int ret;
Note: See TracChangeset for help on using the changeset viewer.