• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/isdn/hisax/
1/*======================================================================
2
3    An elsa_cs PCMCIA client driver
4
5    This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
6
7
8    The contents of this file are subject to the Mozilla Public
9    License Version 1.1 (the "License"); you may not use this file
10    except in compliance with the License. You may obtain a copy of
11    the License at http://www.mozilla.org/MPL/
12
13    Software distributed under the License is distributed on an "AS
14    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15    implied. See the License for the specific language governing
16    rights and limitations under the License.
17
18    The initial developer of the original code is David A. Hinds
19    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
20    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
21
22    Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
23    Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
24
25    Alternatively, the contents of this file may be used under the
26    terms of the GNU General Public License version 2 (the "GPL"), in
27    which case the provisions of the GPL are applicable instead of the
28    above.  If you wish to allow the use of your version of this file
29    only under the terms of the GPL and not to allow others to use
30    your version of this file under the MPL, indicate your decision
31    by deleting the provisions above and replace them with the notice
32    and other provisions required by the GPL.  If you do not delete
33    the provisions above, a recipient may use your version of this
34    file under either the MPL or the GPL.
35
36======================================================================*/
37
38#include <linux/module.h>
39#include <linux/kernel.h>
40#include <linux/init.h>
41#include <linux/ptrace.h>
42#include <linux/slab.h>
43#include <linux/string.h>
44#include <linux/timer.h>
45#include <linux/ioport.h>
46#include <asm/io.h>
47#include <asm/system.h>
48
49#include <pcmcia/cs.h>
50#include <pcmcia/cistpl.h>
51#include <pcmcia/cisreg.h>
52#include <pcmcia/ds.h>
53#include "hisax_cfg.h"
54
55MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
56MODULE_AUTHOR("Klaus Lichtenwalder");
57MODULE_LICENSE("Dual MPL/GPL");
58
59
60/*====================================================================*/
61
62/* Parameters that can be set with 'insmod' */
63
64static int protocol = 2;        /* EURO-ISDN Default */
65module_param(protocol, int, 0);
66
67/*====================================================================*/
68
69/*
70   The event() function is this driver's Card Services event handler.
71   It will be called by Card Services when an appropriate card status
72   event is received.  The config() and release() entry points are
73   used to configure or release a socket, in response to card insertion
74   and ejection events.  They are invoked from the elsa_cs event
75   handler.
76*/
77
78static int elsa_cs_config(struct pcmcia_device *link) __devinit ;
79static void elsa_cs_release(struct pcmcia_device *link);
80
81/*
82   The attach() and detach() entry points are used to create and destroy
83   "instances" of the driver, where each instance represents everything
84   needed to manage one actual PCMCIA card.
85*/
86
87static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit;
88
89typedef struct local_info_t {
90	struct pcmcia_device	*p_dev;
91    int                 busy;
92    int			cardnr;
93} local_info_t;
94
95/*======================================================================
96
97    elsa_cs_attach() creates an "instance" of the driver, allocatingx
98    local data structures for one device.  The device is registered
99    with Card Services.
100
101    The dev_link structure is initialized, but we don't actually
102    configure the card at this point -- we wait until we receive a
103    card insertion event.
104
105======================================================================*/
106
107static int __devinit elsa_cs_probe(struct pcmcia_device *link)
108{
109    local_info_t *local;
110
111    dev_dbg(&link->dev, "elsa_cs_attach()\n");
112
113    /* Allocate space for private device-specific data */
114    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
115    if (!local) return -ENOMEM;
116
117    local->p_dev = link;
118    link->priv = local;
119
120    local->cardnr = -1;
121
122    /*
123      General socket configuration defaults can go here.  In this
124      client, we assume very little, and rely on the CIS for almost
125      everything.  In most clients, many details (i.e., number, sizes,
126      and attributes of IO windows) are fixed by the nature of the
127      device, and can be hard-wired here.
128    */
129    link->resource[0]->end = 8;
130    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
131
132    link->conf.Attributes = CONF_ENABLE_IRQ;
133    link->conf.IntType = INT_MEMORY_AND_IO;
134
135    return elsa_cs_config(link);
136} /* elsa_cs_attach */
137
138/*======================================================================
139
140    This deletes a driver "instance".  The device is de-registered
141    with Card Services.  If it has been released, all local data
142    structures are freed.  Otherwise, the structures will be freed
143    when the device is released.
144
145======================================================================*/
146
147static void __devexit elsa_cs_detach(struct pcmcia_device *link)
148{
149	local_info_t *info = link->priv;
150
151	dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
152
153	info->busy = 1;
154	elsa_cs_release(link);
155
156	kfree(info);
157} /* elsa_cs_detach */
158
159/*======================================================================
160
161    elsa_cs_config() is scheduled to run after a CARD_INSERTION event
162    is received, to configure the PCMCIA socket, and to make the
163    device available to the system.
164
165======================================================================*/
166
167static int elsa_cs_configcheck(struct pcmcia_device *p_dev,
168			       cistpl_cftable_entry_t *cf,
169			       cistpl_cftable_entry_t *dflt,
170			       unsigned int vcc,
171			       void *priv_data)
172{
173	int j;
174
175	p_dev->io_lines = 3;
176
177	if ((cf->io.nwin > 0) && cf->io.win[0].base) {
178		printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
179		p_dev->resource[0]->start = cf->io.win[0].base;
180		if (!pcmcia_request_io(p_dev))
181			return 0;
182	} else {
183		printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
184		for (j = 0x2f0; j > 0x100; j -= 0x10) {
185			p_dev->resource[0]->start = j;
186			if (!pcmcia_request_io(p_dev))
187				return 0;
188		}
189	}
190	return -ENODEV;
191}
192
193static int __devinit elsa_cs_config(struct pcmcia_device *link)
194{
195    local_info_t *dev;
196    int i;
197    IsdnCard_t icard;
198
199    dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
200    dev = link->priv;
201
202    i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
203    if (i != 0)
204	goto failed;
205
206    if (!link->irq)
207	goto failed;
208
209    i = pcmcia_request_configuration(link, &link->conf);
210    if (i != 0)
211	goto failed;
212
213    /* Finally, report what we've done */
214    dev_info(&link->dev, "index 0x%02x: ",
215	    link->conf.ConfigIndex);
216    if (link->conf.Attributes & CONF_ENABLE_IRQ)
217	printk(", irq %d", link->irq);
218    if (link->resource[0])
219	printk(" & %pR", link->resource[0]);
220    if (link->resource[1])
221	printk(" & %pR", link->resource[1]);
222    printk("\n");
223
224    icard.para[0] = link->irq;
225    icard.para[1] = link->resource[0]->start;
226    icard.protocol = protocol;
227    icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
228
229    i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
230    if (i < 0) {
231	printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
232		"PCMCIA %d with %pR\n", i, link->resource[0]);
233    	elsa_cs_release(link);
234    } else
235    	((local_info_t*)link->priv)->cardnr = i;
236
237    return 0;
238failed:
239    elsa_cs_release(link);
240    return -ENODEV;
241} /* elsa_cs_config */
242
243/*======================================================================
244
245    After a card is removed, elsa_cs_release() will unregister the net
246    device, and release the PCMCIA configuration.  If the device is
247    still open, this will be postponed until it is closed.
248
249======================================================================*/
250
251static void elsa_cs_release(struct pcmcia_device *link)
252{
253    local_info_t *local = link->priv;
254
255    dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
256
257    if (local) {
258    	if (local->cardnr >= 0) {
259    	    /* no unregister function with hisax */
260	    HiSax_closecard(local->cardnr);
261	}
262    }
263
264    pcmcia_disable_device(link);
265} /* elsa_cs_release */
266
267static int elsa_suspend(struct pcmcia_device *link)
268{
269	local_info_t *dev = link->priv;
270
271        dev->busy = 1;
272
273	return 0;
274}
275
276static int elsa_resume(struct pcmcia_device *link)
277{
278	local_info_t *dev = link->priv;
279
280        dev->busy = 0;
281
282	return 0;
283}
284
285static struct pcmcia_device_id elsa_ids[] = {
286	PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
287	PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
288	PCMCIA_DEVICE_NULL
289};
290MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
291
292static struct pcmcia_driver elsa_cs_driver = {
293	.owner		= THIS_MODULE,
294	.drv		= {
295		.name	= "elsa_cs",
296	},
297	.probe		= elsa_cs_probe,
298	.remove		= __devexit_p(elsa_cs_detach),
299	.id_table	= elsa_ids,
300	.suspend	= elsa_suspend,
301	.resume		= elsa_resume,
302};
303
304static int __init init_elsa_cs(void)
305{
306	return pcmcia_register_driver(&elsa_cs_driver);
307}
308
309static void __exit exit_elsa_cs(void)
310{
311	pcmcia_unregister_driver(&elsa_cs_driver);
312}
313
314module_init(init_elsa_cs);
315module_exit(exit_elsa_cs);
316