teles_cs.c 5.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11
/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
/*======================================================================

    A teles S0 PCMCIA client driver

    Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
    Written by Christof Petig, christof.petig@wtal.de
    
    Also inspired by ELSA PCMCIA driver 
    by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
    
L
Lucas De Marchi 已提交
12
    Extensions to new hisax_pcmcia by Karsten Keil
L
Linus Torvalds 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

    minor changes to be compatible with kernel 2.4.x
    by Jan.Schubert@GMX.li

======================================================================*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/system.h>

#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"

MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
MODULE_LICENSE("GPL");


/*====================================================================*/

/* Parameters that can be set with 'insmod' */

static int protocol = 2;        /* EURO-ISDN Default */
module_param(protocol, int, 0);

47
static int teles_cs_config(struct pcmcia_device *link) __devinit ;
48
static void teles_cs_release(struct pcmcia_device *link);
49
static void teles_detach(struct pcmcia_device *p_dev) __devexit ;
L
Linus Torvalds 已提交
50 51

typedef struct local_info_t {
52
	struct pcmcia_device	*p_dev;
L
Linus Torvalds 已提交
53 54 55 56
    int                 busy;
    int			cardnr;
} local_info_t;

57
static int __devinit teles_probe(struct pcmcia_device *link)
L
Linus Torvalds 已提交
58 59 60
{
    local_info_t *local;

61
    dev_dbg(&link->dev, "teles_attach()\n");
L
Linus Torvalds 已提交
62 63

    /* Allocate space for private device-specific data */
64
    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
65
    if (!local) return -ENOMEM;
L
Linus Torvalds 已提交
66
    local->cardnr = -1;
67

68
    local->p_dev = link;
69
    link->priv = local;
L
Linus Torvalds 已提交
70

71
    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
L
Linus Torvalds 已提交
72

73
    return teles_cs_config(link);
L
Linus Torvalds 已提交
74 75
} /* teles_attach */

76
static void __devexit teles_detach(struct pcmcia_device *link)
L
Linus Torvalds 已提交
77
{
78
	local_info_t *info = link->priv;
L
Linus Torvalds 已提交
79

80
	dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
L
Linus Torvalds 已提交
81

82 83
	info->busy = 1;
	teles_cs_release(link);
L
Linus Torvalds 已提交
84

85
	kfree(info);
L
Linus Torvalds 已提交
86 87
} /* teles_detach */

88
static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
L
Linus Torvalds 已提交
89
{
90 91
	int j;

92
	p_dev->io_lines = 5;
93 94 95
	p_dev->resource[0]->end = 96;
	p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
96

97
	if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
98
		printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
99
		if (!pcmcia_request_io(p_dev))
100 101 102 103
			return 0;
	} else {
		printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
		for (j = 0x2f0; j > 0x100; j -= 0x10) {
104 105
			p_dev->resource[0]->start = j;
			if (!pcmcia_request_io(p_dev))
106 107 108 109
				return 0;
		}
	}
	return -ENODEV;
L
Linus Torvalds 已提交
110 111
}

112
static int __devinit teles_cs_config(struct pcmcia_device *link)
L
Linus Torvalds 已提交
113
{
114
    int i;
L
Linus Torvalds 已提交
115 116
    IsdnCard_t icard;

117
    dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
L
Linus Torvalds 已提交
118

119
    i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
120
    if (i != 0)
L
Linus Torvalds 已提交
121 122
	goto cs_failed;

123
    if (!link->irq)
L
Linus Torvalds 已提交
124 125
        goto cs_failed;

126
    i = pcmcia_enable_device(link);
127
    if (i != 0)
L
Linus Torvalds 已提交
128 129
      goto cs_failed;

130
    icard.para[0] = link->irq;
131
    icard.para[1] = link->resource[0]->start;
L
Linus Torvalds 已提交
132 133 134 135 136 137
    icard.protocol = protocol;
    icard.typ = ISDN_CTYPE_TELESPCMCIA;
    
    i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
    if (i < 0) {
    	printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
138
			i, (unsigned int) link->resource[0]->start);
L
Linus Torvalds 已提交
139
    	teles_cs_release(link);
140 141 142 143 144
	return -ENODEV;
    }

    ((local_info_t*)link->priv)->cardnr = i;
    return 0;
L
Linus Torvalds 已提交
145 146 147

cs_failed:
    teles_cs_release(link);
148
    return -ENODEV;
L
Linus Torvalds 已提交
149 150
} /* teles_cs_config */

151
static void teles_cs_release(struct pcmcia_device *link)
L
Linus Torvalds 已提交
152 153 154
{
    local_info_t *local = link->priv;

155
    dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
L
Linus Torvalds 已提交
156 157 158 159 160 161 162

    if (local) {
    	if (local->cardnr >= 0) {
    	    /* no unregister function with hisax */
	    HiSax_closecard(local->cardnr);
	}
    }
163

164
    pcmcia_disable_device(link);
L
Linus Torvalds 已提交
165 166
} /* teles_cs_release */

167
static int teles_suspend(struct pcmcia_device *link)
168 169 170 171 172 173 174 175
{
	local_info_t *dev = link->priv;

        dev->busy = 1;

	return 0;
}

176
static int teles_resume(struct pcmcia_device *link)
177 178 179 180 181 182 183 184
{
	local_info_t *dev = link->priv;

        dev->busy = 0;

	return 0;
}

L
Linus Torvalds 已提交
185

186 187 188 189 190 191
static struct pcmcia_device_id teles_ids[] = {
	PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
	PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, teles_ids);

L
Linus Torvalds 已提交
192 193
static struct pcmcia_driver teles_cs_driver = {
	.owner		= THIS_MODULE,
194
	.name		= "teles_cs",
195
	.probe		= teles_probe,
196
	.remove		= __devexit_p(teles_detach),
197
	.id_table       = teles_ids,
198 199
	.suspend	= teles_suspend,
	.resume		= teles_resume,
L
Linus Torvalds 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213
};

static int __init init_teles_cs(void)
{
	return pcmcia_register_driver(&teles_cs_driver);
}

static void __exit exit_teles_cs(void)
{
	pcmcia_unregister_driver(&teles_cs_driver);
}

module_init(init_teles_cs);
module_exit(exit_teles_cs);