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_types.h>
50#include <pcmcia/cs.h>
51#include <pcmcia/cistpl.h>
52#include <pcmcia/cisreg.h>
53#include <pcmcia/ds.h>
54#include "hisax_cfg.h"
55
56MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
57MODULE_AUTHOR("Klaus Lichtenwalder");
58MODULE_LICENSE("Dual MPL/GPL");
59
60/*
61   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
62   you do not define PCMCIA_DEBUG at all, all the debug code will be
63   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
64   be present but disabled -- but it can then be enabled for specific
65   modules at load time with a 'pc_debug=#' option to insmod.
66*/
67
68#ifdef PCMCIA_DEBUG
69static int pc_debug = PCMCIA_DEBUG;
70module_param(pc_debug, int, 0);
71#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
72static char *version =
73"elsa_cs.c $Revision: 1.1.1.1 $ $Date: 2007/08/03 18:52:35 $ (K.Lichtenwalder)";
74#else
75#define DEBUG(n, args...)
76#endif
77
78/*====================================================================*/
79
80/* Parameters that can be set with 'insmod' */
81
82static int protocol = 2;        /* EURO-ISDN Default */
83module_param(protocol, int, 0);
84
85/*====================================================================*/
86
87/*
88   The event() function is this driver's Card Services event handler.
89   It will be called by Card Services when an appropriate card status
90   event is received.  The config() and release() entry points are
91   used to configure or release a socket, in response to card insertion
92   and ejection events.  They are invoked from the elsa_cs event
93   handler.
94*/
95
96static int elsa_cs_config(struct pcmcia_device *link);
97static void elsa_cs_release(struct pcmcia_device *link);
98
99/*
100   The attach() and detach() entry points are used to create and destroy
101   "instances" of the driver, where each instance represents everything
102   needed to manage one actual PCMCIA card.
103*/
104
105static void elsa_cs_detach(struct pcmcia_device *p_dev);
106
107/*
108   A driver needs to provide a dev_node_t structure for each device
109   on a card.  In some cases, there is only one device per card (for
110   example, ethernet cards, modems).  In other cases, there may be
111   many actual or logical devices (SCSI adapters, memory cards with
112   multiple partitions).  The dev_node_t structures need to be kept
113   in a linked list starting at the 'dev' field of a struct pcmcia_device
114   structure.  We allocate them in the card's private data structure,
115   because they generally shouldn't be allocated dynamically.
116   In this case, we also provide a flag to indicate if a device is
117   "stopped" due to a power management event, or card ejection.  The
118   device IO routines can use a flag like this to throttle IO to a
119   card that is not ready to accept it.
120*/
121
122typedef struct local_info_t {
123	struct pcmcia_device	*p_dev;
124    dev_node_t          node;
125    int                 busy;
126    int			cardnr;
127} local_info_t;
128
129/*======================================================================
130
131    elsa_cs_attach() creates an "instance" of the driver, allocatingx
132    local data structures for one device.  The device is registered
133    with Card Services.
134
135    The dev_link structure is initialized, but we don't actually
136    configure the card at this point -- we wait until we receive a
137    card insertion event.
138
139======================================================================*/
140
141static int elsa_cs_probe(struct pcmcia_device *link)
142{
143    local_info_t *local;
144
145    DEBUG(0, "elsa_cs_attach()\n");
146
147    /* Allocate space for private device-specific data */
148    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
149    if (!local) return -ENOMEM;
150
151    local->p_dev = link;
152    link->priv = local;
153
154    local->cardnr = -1;
155
156    /* Interrupt setup */
157    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
158    link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID;
159    link->irq.Handler = NULL;
160
161    /*
162      General socket configuration defaults can go here.  In this
163      client, we assume very little, and rely on the CIS for almost
164      everything.  In most clients, many details (i.e., number, sizes,
165      and attributes of IO windows) are fixed by the nature of the
166      device, and can be hard-wired here.
167    */
168    link->io.NumPorts1 = 8;
169    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
170    link->io.IOAddrLines = 3;
171
172    link->conf.Attributes = CONF_ENABLE_IRQ;
173    link->conf.IntType = INT_MEMORY_AND_IO;
174
175    return elsa_cs_config(link);
176} /* elsa_cs_attach */
177
178/*======================================================================
179
180    This deletes a driver "instance".  The device is de-registered
181    with Card Services.  If it has been released, all local data
182    structures are freed.  Otherwise, the structures will be freed
183    when the device is released.
184
185======================================================================*/
186
187static void elsa_cs_detach(struct pcmcia_device *link)
188{
189	local_info_t *info = link->priv;
190
191	DEBUG(0, "elsa_cs_detach(0x%p)\n", link);
192
193	info->busy = 1;
194	elsa_cs_release(link);
195
196	kfree(info);
197} /* elsa_cs_detach */
198
199/*======================================================================
200
201    elsa_cs_config() is scheduled to run after a CARD_INSERTION event
202    is received, to configure the PCMCIA socket, and to make the
203    device available to the system.
204
205======================================================================*/
206static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
207                     cisparse_t *parse)
208{
209    int i = pcmcia_get_tuple_data(handle, tuple);
210    if (i != CS_SUCCESS) return i;
211    return pcmcia_parse_tuple(handle, tuple, parse);
212}
213
214static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
215                     cisparse_t *parse)
216{
217    int i = pcmcia_get_first_tuple(handle, tuple);
218    if (i != CS_SUCCESS) return i;
219    return get_tuple(handle, tuple, parse);
220}
221
222static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
223                     cisparse_t *parse)
224{
225    int i = pcmcia_get_next_tuple(handle, tuple);
226    if (i != CS_SUCCESS) return i;
227    return get_tuple(handle, tuple, parse);
228}
229
230static int elsa_cs_config(struct pcmcia_device *link)
231{
232    tuple_t tuple;
233    cisparse_t parse;
234    local_info_t *dev;
235    int i, j, last_fn;
236    u_short buf[128];
237    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
238    IsdnCard_t icard;
239
240    DEBUG(0, "elsa_config(0x%p)\n", link);
241    dev = link->priv;
242
243    tuple.TupleData = (cisdata_t *)buf;
244    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
245    tuple.Attributes = 0;
246    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
247    i = first_tuple(link, &tuple, &parse);
248    while (i == CS_SUCCESS) {
249        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
250            printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
251            link->conf.ConfigIndex = cf->index;
252            link->io.BasePort1 = cf->io.win[0].base;
253            i = pcmcia_request_io(link, &link->io);
254            if (i == CS_SUCCESS) break;
255        } else {
256          printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
257          link->conf.ConfigIndex = cf->index;
258          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
259            link->io.BasePort1 = j;
260            i = pcmcia_request_io(link, &link->io);
261            if (i == CS_SUCCESS) break;
262          }
263          break;
264        }
265        i = next_tuple(link, &tuple, &parse);
266    }
267
268    if (i != CS_SUCCESS) {
269	last_fn = RequestIO;
270	goto cs_failed;
271    }
272
273    i = pcmcia_request_irq(link, &link->irq);
274    if (i != CS_SUCCESS) {
275        link->irq.AssignedIRQ = 0;
276	last_fn = RequestIRQ;
277        goto cs_failed;
278    }
279
280    i = pcmcia_request_configuration(link, &link->conf);
281    if (i != CS_SUCCESS) {
282      last_fn = RequestConfiguration;
283      goto cs_failed;
284    }
285
286    /* At this point, the dev_node_t structure(s) should be
287       initialized and arranged in a linked list at link->dev. *//*  */
288    sprintf(dev->node.dev_name, "elsa");
289    dev->node.major = dev->node.minor = 0x0;
290
291    link->dev_node = &dev->node;
292
293    /* Finally, report what we've done */
294    printk(KERN_INFO "%s: index 0x%02x: ",
295           dev->node.dev_name, link->conf.ConfigIndex);
296    if (link->conf.Attributes & CONF_ENABLE_IRQ)
297        printk(", irq %d", link->irq.AssignedIRQ);
298    if (link->io.NumPorts1)
299        printk(", io 0x%04x-0x%04x", link->io.BasePort1,
300               link->io.BasePort1+link->io.NumPorts1-1);
301    if (link->io.NumPorts2)
302        printk(" & 0x%04x-0x%04x", link->io.BasePort2,
303               link->io.BasePort2+link->io.NumPorts2-1);
304    printk("\n");
305
306    icard.para[0] = link->irq.AssignedIRQ;
307    icard.para[1] = link->io.BasePort1;
308    icard.protocol = protocol;
309    icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
310
311    i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
312    if (i < 0) {
313    	printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#x\n",
314    		i, link->io.BasePort1);
315    	elsa_cs_release(link);
316    } else
317    	((local_info_t*)link->priv)->cardnr = i;
318
319    return 0;
320cs_failed:
321    cs_error(link, last_fn, i);
322    elsa_cs_release(link);
323    return -ENODEV;
324} /* elsa_cs_config */
325
326/*======================================================================
327
328    After a card is removed, elsa_cs_release() will unregister the net
329    device, and release the PCMCIA configuration.  If the device is
330    still open, this will be postponed until it is closed.
331
332======================================================================*/
333
334static void elsa_cs_release(struct pcmcia_device *link)
335{
336    local_info_t *local = link->priv;
337
338    DEBUG(0, "elsa_cs_release(0x%p)\n", link);
339
340    if (local) {
341    	if (local->cardnr >= 0) {
342    	    /* no unregister function with hisax */
343	    HiSax_closecard(local->cardnr);
344	}
345    }
346
347    pcmcia_disable_device(link);
348} /* elsa_cs_release */
349
350static int elsa_suspend(struct pcmcia_device *link)
351{
352	local_info_t *dev = link->priv;
353
354        dev->busy = 1;
355
356	return 0;
357}
358
359static int elsa_resume(struct pcmcia_device *link)
360{
361	local_info_t *dev = link->priv;
362
363        dev->busy = 0;
364
365	return 0;
366}
367
368static struct pcmcia_device_id elsa_ids[] = {
369	PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
370	PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
371	PCMCIA_DEVICE_NULL
372};
373MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
374
375static struct pcmcia_driver elsa_cs_driver = {
376	.owner		= THIS_MODULE,
377	.drv		= {
378		.name	= "elsa_cs",
379	},
380	.probe		= elsa_cs_probe,
381	.remove		= elsa_cs_detach,
382	.id_table	= elsa_ids,
383	.suspend	= elsa_suspend,
384	.resume		= elsa_resume,
385};
386
387static int __init init_elsa_cs(void)
388{
389	return pcmcia_register_driver(&elsa_cs_driver);
390}
391
392static void __exit exit_elsa_cs(void)
393{
394	pcmcia_unregister_driver(&elsa_cs_driver);
395}
396
397module_init(init_elsa_cs);
398module_exit(exit_elsa_cs);
399