Changeset 00aece0 in mainline for uspace/drv/bus/isa/isa.c


Ignore:
Timestamp:
2012-02-18T16:47:38Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4449c6c
Parents:
bd5f3b7 (diff), f943dd3 (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 mainline changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/isa/isa.c

    rbd5f3b7 r00aece0  
    22 * Copyright (c) 2010 Lenka Trochtova
    33 * Copyright (c) 2011 Jiri Svoboda
     4 * Copyright (c) 2011 Jan Vesely
    45 * All rights reserved.
    56 *
     
    3738 */
    3839
     40#include <adt/list.h>
    3941#include <assert.h>
    4042#include <stdio.h>
     
    5052#include <dirent.h>
    5153#include <fcntl.h>
     54#include <ipc/irc.h>
     55#include <ipc/services.h>
     56#include <sysinfo.h>
     57#include <ns.h>
    5258#include <sys/stat.h>
     59#include <ipc/irc.h>
     60#include <ipc/services.h>
     61#include <sysinfo.h>
     62#include <ns.h>
    5363
    5464#include <ddf/driver.h>
     
    6070#include <device/hw_res.h>
    6171
     72#include "i8237.h"
     73
    6274#define NAME "isa"
    6375#define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
    6476
    65 /** Obtain soft-state pointer from function node pointer */
    66 #define ISA_FUN(fnode) ((isa_fun_t *) ((fnode)->driver_data))
    67 
    68 #define ISA_MAX_HW_RES 4
     77/** Obtain soft-state from device node */
     78#define ISA_BUS(dev) ((isa_bus_t *) ((dev)->driver_data))
     79
     80/** Obtain soft-state from function node */
     81#define ISA_FUN(fun) ((isa_fun_t *) ((fun)->driver_data))
     82
     83#define ISA_MAX_HW_RES 5
     84
     85typedef struct {
     86        fibril_mutex_t mutex;
     87        ddf_dev_t *dev;
     88        ddf_fun_t *fctl;
     89        list_t functions;
     90} isa_bus_t;
    6991
    7092typedef struct isa_fun {
     93        fibril_mutex_t mutex;
    7194        ddf_fun_t *fnode;
    7295        hw_resource_list_t hw_resources;
     96        link_t bus_link;
    7397} isa_fun_t;
    7498
     
    83107static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
    84108{
    85         /* TODO */
    86 
    87         return false;
     109        /* This is an old ugly way, copied from pci driver */
     110        assert(fnode);
     111        isa_fun_t *isa_fun = fnode->driver_data;
     112
     113        sysarg_t apic;
     114        sysarg_t i8259;
     115
     116        async_sess_t *irc_sess = NULL;
     117
     118        if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
     119            || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
     120                irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
     121                    SERVICE_IRC, 0, 0);
     122        }
     123
     124        if (!irc_sess)
     125                return false;
     126
     127        assert(isa_fun);
     128        const hw_resource_list_t *res = &isa_fun->hw_resources;
     129        assert(res);
     130        for (size_t i = 0; i < res->count; ++i) {
     131                if (res->resources[i].type == INTERRUPT) {
     132                        const int irq = res->resources[i].res.interrupt.irq;
     133
     134                        async_exch_t *exch = async_exchange_begin(irc_sess);
     135                        const int rc =
     136                            async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
     137                        async_exchange_end(exch);
     138
     139                        if (rc != EOK) {
     140                                async_hangup(irc_sess);
     141                                return false;
     142                        }
     143                }
     144        }
     145
     146        async_hangup(irc_sess);
     147        return true;
     148}
     149
     150static int isa_dma_channel_fun_setup(ddf_fun_t *fnode,
     151    unsigned int channel, uint32_t pa, uint16_t size, uint8_t mode)
     152{
     153        assert(fnode);
     154        isa_fun_t *isa_fun = fnode->driver_data;
     155        const hw_resource_list_t *res = &isa_fun->hw_resources;
     156        assert(res);
     157       
     158        const unsigned int ch = channel;
     159        for (size_t i = 0; i < res->count; ++i) {
     160                if (((res->resources[i].type == DMA_CHANNEL_16) &&
     161                    (res->resources[i].res.dma_channel.dma16 == ch)) ||
     162                    ((res->resources[i].type == DMA_CHANNEL_8) &&
     163                    (res->resources[i].res.dma_channel.dma8 == ch))) {
     164                        return dma_setup_channel(channel, pa, size, mode);
     165                }
     166        }
     167       
     168        return EINVAL;
    88169}
    89170
    90171static hw_res_ops_t isa_fun_hw_res_ops = {
    91         &isa_get_fun_resources,
    92         &isa_enable_fun_interrupt
     172        .get_resource_list = isa_get_fun_resources,
     173        .enable_interrupt = isa_enable_fun_interrupt,
     174        .dma_channel_setup = isa_dma_channel_fun_setup,
    93175};
    94176
    95177static ddf_dev_ops_t isa_fun_ops;
    96178
    97 static int isa_add_device(ddf_dev_t *dev);
     179static int isa_dev_add(ddf_dev_t *dev);
     180static int isa_dev_remove(ddf_dev_t *dev);
     181static int isa_fun_online(ddf_fun_t *fun);
     182static int isa_fun_offline(ddf_fun_t *fun);
    98183
    99184/** The isa device driver's standard operations */
    100185static driver_ops_t isa_ops = {
    101         .add_device = &isa_add_device
     186        .dev_add = &isa_dev_add,
     187        .dev_remove = &isa_dev_remove,
     188        .fun_online = &isa_fun_online,
     189        .fun_offline = &isa_fun_offline
    102190};
    103191
     
    108196};
    109197
    110 static isa_fun_t *isa_fun_create(ddf_dev_t *dev, const char *name)
    111 {
    112         isa_fun_t *fun = calloc(1, sizeof(isa_fun_t));
     198static isa_fun_t *isa_fun_create(isa_bus_t *isa, const char *name)
     199{
     200        ddf_fun_t *fnode = ddf_fun_create(isa->dev, fun_inner, name);
     201        if (fnode == NULL)
     202                return NULL;
     203
     204        isa_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(isa_fun_t));
    113205        if (fun == NULL)
    114206                return NULL;
    115207
    116         ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name);
    117         if (fnode == NULL) {
    118                 free(fun);
    119                 return NULL;
    120         }
    121 
     208        fibril_mutex_initialize(&fun->mutex);
    122209        fun->fnode = fnode;
    123         fnode->driver_data = fun;
    124210        return fun;
    125211}
     
    257343}
    258344
     345static void isa_fun_set_dma(isa_fun_t *fun, int dma)
     346{
     347        size_t count = fun->hw_resources.count;
     348        hw_resource_t *resources = fun->hw_resources.resources;
     349       
     350        if (count < ISA_MAX_HW_RES) {
     351                if ((dma > 0) && (dma < 4)) {
     352                        resources[count].type = DMA_CHANNEL_8;
     353                        resources[count].res.dma_channel.dma8 = dma;
     354                       
     355                        fun->hw_resources.count++;
     356                        ddf_msg(LVL_NOTE, "Added dma 0x%x to function %s", dma,
     357                            fun->fnode->name);
     358                       
     359                        return;
     360                }
     361
     362                if ((dma > 4) && (dma < 8)) {
     363                        resources[count].type = DMA_CHANNEL_16;
     364                        resources[count].res.dma_channel.dma16 = dma;
     365                       
     366                        fun->hw_resources.count++;
     367                        ddf_msg(LVL_NOTE, "Added dma 0x%x to function %s", dma,
     368                            fun->fnode->name);
     369                       
     370                        return;
     371                }
     372               
     373                ddf_msg(LVL_WARN, "Skipped dma 0x%x for function %s", dma,
     374                    fun->fnode->name);
     375        }
     376}
     377
    259378static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
    260379{
     
    282401
    283402        val = skip_spaces(val);
    284         irq = (int)strtol(val, &end, 0x10);
     403        irq = (int) strtol(val, &end, 10);
    285404
    286405        if (val != end)
    287406                isa_fun_set_irq(fun, irq);
     407}
     408
     409static void fun_parse_dma(isa_fun_t *fun, char *val)
     410{
     411        unsigned int dma = 0;
     412        char *end = NULL;
     413       
     414        val = skip_spaces(val);
     415        dma = (unsigned int) strtol(val, &end, 10);
     416       
     417        if (val != end)
     418                isa_fun_set_dma(fun, dma);
    288419}
    289420
     
    379510        if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
    380511            !prop_parse(fun, line, "irq", &fun_parse_irq) &&
     512            !prop_parse(fun, line, "dma", &fun_parse_dma) &&
    381513            !prop_parse(fun, line, "match", &fun_parse_match_id)) {
    382514
     
    388520static void fun_hw_res_alloc(isa_fun_t *fun)
    389521{
    390         fun->hw_resources.resources =
    391             (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
    392 }
    393 
    394 static char *isa_fun_read_info(char *fun_conf, ddf_dev_t *dev)
     522        fun->hw_resources.resources =
     523            (hw_resource_t *) malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
     524}
     525
     526static void fun_hw_res_free(isa_fun_t *fun)
     527{
     528        free(fun->hw_resources.resources);
     529        fun->hw_resources.resources = NULL;
     530}
     531
     532static char *isa_fun_read_info(char *fun_conf, isa_bus_t *isa)
    395533{
    396534        char *line;
     
    415553                return NULL;
    416554
    417         isa_fun_t *fun = isa_fun_create(dev, fun_name);
     555        isa_fun_t *fun = isa_fun_create(isa, fun_name);
    418556        if (fun == NULL) {
    419557                free(fun_name);
     
    448586        (void) ddf_fun_bind(fun->fnode);
    449587
     588        list_append(&fun->bus_link, &isa->functions);
     589
    450590        return fun_conf;
    451591}
    452592
    453 static void fun_conf_parse(char *conf, ddf_dev_t *dev)
     593static void fun_conf_parse(char *conf, isa_bus_t *isa)
    454594{
    455595        while (conf != NULL && *conf != '\0') {
    456                 conf = isa_fun_read_info(conf, dev);
    457         }
    458 }
    459 
    460 static void isa_functions_add(ddf_dev_t *dev)
     596                conf = isa_fun_read_info(conf, isa);
     597        }
     598}
     599
     600static void isa_functions_add(isa_bus_t *isa)
    461601{
    462602        char *fun_conf;
     
    464604        fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
    465605        if (fun_conf != NULL) {
    466                 fun_conf_parse(fun_conf, dev);
     606                fun_conf_parse(fun_conf, isa);
    467607                free(fun_conf);
    468608        }
    469609}
    470610
    471 static int isa_add_device(ddf_dev_t *dev)
    472 {
    473         ddf_msg(LVL_DEBUG, "isa_add_device, device handle = %d",
     611static int isa_dev_add(ddf_dev_t *dev)
     612{
     613        isa_bus_t *isa;
     614
     615        ddf_msg(LVL_DEBUG, "isa_dev_add, device handle = %d",
    474616            (int) dev->handle);
     617
     618        isa = ddf_dev_data_alloc(dev, sizeof(isa_bus_t));
     619        if (isa == NULL)
     620                return ENOMEM;
     621
     622        fibril_mutex_initialize(&isa->mutex);
     623        isa->dev = dev;
     624        list_initialize(&isa->functions);
    475625
    476626        /* Make the bus device more visible. Does not do anything. */
    477627        ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
    478628
    479         ddf_fun_t *ctl = ddf_fun_create(dev, fun_exposed, "ctl");
    480         if (ctl == NULL) {
     629        fibril_mutex_lock(&isa->mutex);
     630
     631        isa->fctl = ddf_fun_create(dev, fun_exposed, "ctl");
     632        if (isa->fctl == NULL) {
    481633                ddf_msg(LVL_ERROR, "Failed creating control function.");
    482634                return EXDEV;
    483635        }
    484636
    485         if (ddf_fun_bind(ctl) != EOK) {
     637        if (ddf_fun_bind(isa->fctl) != EOK) {
     638                ddf_fun_destroy(isa->fctl);
    486639                ddf_msg(LVL_ERROR, "Failed binding control function.");
    487640                return EXDEV;
     
    489642
    490643        /* Add functions as specified in the configuration file. */
    491         isa_functions_add(dev);
     644        isa_functions_add(isa);
    492645        ddf_msg(LVL_NOTE, "Finished enumerating legacy functions");
    493646
     647        fibril_mutex_unlock(&isa->mutex);
     648
    494649        return EOK;
    495650}
    496651
    497 static void isa_init()
     652static int isa_dev_remove(ddf_dev_t *dev)
     653{
     654        isa_bus_t *isa = ISA_BUS(dev);
     655        int rc;
     656
     657        fibril_mutex_lock(&isa->mutex);
     658
     659        while (!list_empty(&isa->functions)) {
     660                isa_fun_t *fun = list_get_instance(list_first(&isa->functions),
     661                    isa_fun_t, bus_link);
     662
     663                rc = ddf_fun_offline(fun->fnode);
     664                if (rc != EOK) {
     665                        fibril_mutex_unlock(&isa->mutex);
     666                        ddf_msg(LVL_ERROR, "Failed offlining %s", fun->fnode->name);
     667                        return rc;
     668                }
     669
     670                rc = ddf_fun_unbind(fun->fnode);
     671                if (rc != EOK) {
     672                        fibril_mutex_unlock(&isa->mutex);
     673                        ddf_msg(LVL_ERROR, "Failed unbinding %s", fun->fnode->name);
     674                        return rc;
     675                }
     676
     677                list_remove(&fun->bus_link);
     678
     679                fun_hw_res_free(fun);
     680                ddf_fun_destroy(fun->fnode);
     681        }
     682
     683        if (ddf_fun_unbind(isa->fctl) != EOK) {
     684                fibril_mutex_unlock(&isa->mutex);
     685                ddf_msg(LVL_ERROR, "Failed unbinding control function.");
     686                return EXDEV;
     687        }
     688
     689        fibril_mutex_unlock(&isa->mutex);
     690
     691        return EOK;
     692}
     693
     694static int isa_fun_online(ddf_fun_t *fun)
     695{
     696        ddf_msg(LVL_DEBUG, "isa_fun_online()");
     697        return ddf_fun_online(fun);
     698}
     699
     700static int isa_fun_offline(ddf_fun_t *fun)
     701{
     702        ddf_msg(LVL_DEBUG, "isa_fun_offline()");
     703        return ddf_fun_offline(fun);
     704}
     705
     706
     707static void isa_init()
    498708{
    499709        ddf_log_init(NAME, LVL_ERROR);
Note: See TracChangeset for help on using the changeset viewer.