linux/drivers/telephony/ixj_pcmcia.c
<<
>>
Prefs
   1#include "ixj-ver.h"
   2
   3#include <linux/module.h>
   4
   5#include <linux/init.h>
   6#include <linux/kernel.h>       /* printk() */
   7#include <linux/fs.h>           /* everything... */
   8#include <linux/errno.h>        /* error codes */
   9#include <linux/slab.h>
  10
  11#include <pcmcia/cs_types.h>
  12#include <pcmcia/cs.h>
  13#include <pcmcia/cistpl.h>
  14#include <pcmcia/ds.h>
  15
  16#include "ixj.h"
  17
  18/*
  19 *      PCMCIA service support for Quicknet cards
  20 */
  21 
  22#ifdef PCMCIA_DEBUG
  23static int pc_debug = PCMCIA_DEBUG;
  24module_param(pc_debug, int, 0644);
  25#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
  26#else
  27#define DEBUG(n, args...)
  28#endif
  29
  30typedef struct ixj_info_t {
  31        int ndev;
  32        dev_node_t node;
  33        struct ixj *port;
  34} ixj_info_t;
  35
  36static void ixj_detach(struct pcmcia_device *p_dev);
  37static int ixj_config(struct pcmcia_device * link);
  38static void ixj_cs_release(struct pcmcia_device * link);
  39
  40static int ixj_probe(struct pcmcia_device *p_dev)
  41{
  42        DEBUG(0, "ixj_attach()\n");
  43        /* Create new ixj device */
  44        p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
  45        p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
  46        p_dev->io.IOAddrLines = 3;
  47        p_dev->conf.IntType = INT_MEMORY_AND_IO;
  48        p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
  49        if (!p_dev->priv) {
  50                return -ENOMEM;
  51        }
  52
  53        return ixj_config(p_dev);
  54}
  55
  56static void ixj_detach(struct pcmcia_device *link)
  57{
  58        DEBUG(0, "ixj_detach(0x%p)\n", link);
  59
  60        ixj_cs_release(link);
  61
  62        kfree(link->priv);
  63}
  64
  65#define CS_CHECK(fn, ret) \
  66do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
  67
  68static void ixj_get_serial(struct pcmcia_device * link, IXJ * j)
  69{
  70        char *str;
  71        int i, place;
  72        DEBUG(0, "ixj_get_serial(0x%p)\n", link);
  73
  74        str = link->prod_id[0];
  75        if (!str)
  76                goto cs_failed;
  77        printk("%s", str);
  78        str = link->prod_id[1];
  79        if (!str)
  80                goto cs_failed;
  81        printk(" %s", str);
  82        str = link->prod_id[2];
  83        if (!str)
  84                goto cs_failed;
  85        place = 1;
  86        for (i = strlen(str) - 1; i >= 0; i--) {
  87                switch (str[i]) {
  88                case '0':
  89                case '1':
  90                case '2':
  91                case '3':
  92                case '4':
  93                case '5':
  94                case '6':
  95                case '7':
  96                case '8':
  97                case '9':
  98                        j->serial += (str[i] - 48) * place;
  99                        break;
 100                case 'A':
 101                case 'B':
 102                case 'C':
 103                case 'D':
 104                case 'E':
 105                case 'F':
 106                        j->serial += (str[i] - 55) * place;
 107                        break;
 108                case 'a':
 109                case 'b':
 110                case 'c':
 111                case 'd':
 112                case 'e':
 113                case 'f':
 114                        j->serial += (str[i] - 87) * place;
 115                        break;
 116                }
 117                place = place * 0x10;
 118        }
 119        str = link->prod_id[3];
 120        if (!str)
 121                goto cs_failed;
 122        printk(" version %s\n", str);
 123      cs_failed:
 124        return;
 125}
 126
 127static int ixj_config(struct pcmcia_device * link)
 128{
 129        IXJ *j;
 130        ixj_info_t *info;
 131        tuple_t tuple;
 132        u_short buf[128];
 133        cisparse_t parse;
 134        cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
 135        cistpl_cftable_entry_t dflt =
 136        {
 137                0
 138        };
 139        int last_ret, last_fn;
 140        info = link->priv;
 141        DEBUG(0, "ixj_config(0x%p)\n", link);
 142        tuple.TupleData = (cisdata_t *) buf;
 143        tuple.TupleOffset = 0;
 144        tuple.TupleDataMax = 255;
 145        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 146        tuple.Attributes = 0;
 147        CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 148        while (1) {
 149                if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
 150                                pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 151                        goto next_entry;
 152                if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
 153                        cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
 154                        link->conf.ConfigIndex = cfg->index;
 155                        link->io.BasePort1 = io->win[0].base;
 156                        link->io.NumPorts1 = io->win[0].len;
 157                        if (io->nwin == 2) {
 158                                link->io.BasePort2 = io->win[1].base;
 159                                link->io.NumPorts2 = io->win[1].len;
 160                        }
 161                        if (pcmcia_request_io(link, &link->io) != 0)
 162                                goto next_entry;
 163                        /* If we've got this far, we're done */
 164                        break;
 165                }
 166              next_entry:
 167                if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 168                        dflt = *cfg;
 169                CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 170        }
 171
 172        CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 173
 174        /*
 175         *      Register the card with the core.
 176         */     
 177        j=ixj_pcmcia_probe(link->io.BasePort1,link->io.BasePort1 + 0x10);
 178
 179        info->ndev = 1;
 180        info->node.major = PHONE_MAJOR;
 181        link->dev_node = &info->node;
 182        ixj_get_serial(link, j);
 183        return 0;
 184      cs_failed:
 185        cs_error(link, last_fn, last_ret);
 186        ixj_cs_release(link);
 187        return -ENODEV;
 188}
 189
 190static void ixj_cs_release(struct pcmcia_device *link)
 191{
 192        ixj_info_t *info = link->priv;
 193        DEBUG(0, "ixj_cs_release(0x%p)\n", link);
 194        info->ndev = 0;
 195        pcmcia_disable_device(link);
 196}
 197
 198static struct pcmcia_device_id ixj_ids[] = {
 199        PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
 200        PCMCIA_DEVICE_NULL
 201};
 202MODULE_DEVICE_TABLE(pcmcia, ixj_ids);
 203
 204static struct pcmcia_driver ixj_driver = {
 205        .owner          = THIS_MODULE,
 206        .drv            = {
 207                .name   = "ixj_cs",
 208        },
 209        .probe          = ixj_probe,
 210        .remove         = ixj_detach,
 211        .id_table       = ixj_ids,
 212};
 213
 214static int __init ixj_pcmcia_init(void)
 215{
 216        return pcmcia_register_driver(&ixj_driver);
 217}
 218
 219static void ixj_pcmcia_exit(void)
 220{
 221        pcmcia_unregister_driver(&ixj_driver);
 222}
 223
 224module_init(ixj_pcmcia_init);
 225module_exit(ixj_pcmcia_exit);
 226
 227MODULE_LICENSE("GPL");
 228