Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6.git] / drivers / isdn / hardware / avm / avm_cs.c
1 /* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $
2  *
3  * A PCMCIA client driver for AVM B1/M1/M2
4  *
5  * Copyright 1999 by Carsten Paeth <calle@calle.de>
6  *
7  * This software may be used and distributed according to the terms
8  * of the GNU General Public License, incorporated herein by reference.
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/ptrace.h>
16 #include <linux/slab.h>
17 #include <linux/string.h>
18 #include <linux/tty.h>
19 #include <linux/serial.h>
20 #include <linux/major.h>
21 #include <asm/io.h>
22 #include <asm/system.h>
23
24 #include <pcmcia/cs_types.h>
25 #include <pcmcia/cs.h>
26 #include <pcmcia/cistpl.h>
27 #include <pcmcia/ciscode.h>
28 #include <pcmcia/ds.h>
29 #include <pcmcia/cisreg.h>
30
31 #include <linux/skbuff.h>
32 #include <linux/capi.h>
33 #include <linux/b1lli.h>
34 #include <linux/b1pcmcia.h>
35
36 /*====================================================================*/
37
38 MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
39 MODULE_AUTHOR("Carsten Paeth");
40 MODULE_LICENSE("GPL");
41
42 /*====================================================================*/
43
44 /*
45    The event() function is this driver's Card Services event handler.
46    It will be called by Card Services when an appropriate card status
47    event is received.  The config() and release() entry points are
48    used to configure or release a socket, in response to card insertion
49    and ejection events.  They are invoked from the skeleton event
50    handler.
51 */
52
53 static int avmcs_config(struct pcmcia_device *link);
54 static void avmcs_release(struct pcmcia_device *link);
55
56 /*
57    The attach() and detach() entry points are used to create and destroy
58    "instances" of the driver, where each instance represents everything
59    needed to manage one actual PCMCIA card.
60 */
61
62 static void avmcs_detach(struct pcmcia_device *p_dev);
63
64 /*
65    A linked list of "instances" of the skeleton device.  Each actual
66    PCMCIA card corresponds to one device instance, and is described
67    by one struct pcmcia_device structure (defined in ds.h).
68
69    You may not want to use a linked list for this -- for example, the
70    memory card driver uses an array of struct pcmcia_device pointers, where minor
71    device numbers are used to derive the corresponding array index.
72 */
73
74 /*
75    A driver needs to provide a dev_node_t structure for each device
76    on a card.  In some cases, there is only one device per card (for
77    example, ethernet cards, modems).  In other cases, there may be
78    many actual or logical devices (SCSI adapters, memory cards with
79    multiple partitions).  The dev_node_t structures need to be kept
80    in a linked list starting at the 'dev' field of a struct pcmcia_device
81    structure.  We allocate them in the card's private data structure,
82    because they generally can't be allocated dynamically.
83 */
84    
85 typedef struct local_info_t {
86     dev_node_t  node;
87 } local_info_t;
88
89 /*======================================================================
90
91     avmcs_attach() creates an "instance" of the driver, allocating
92     local data structures for one device.  The device is registered
93     with Card Services.
94
95     The dev_link structure is initialized, but we don't actually
96     configure the card at this point -- we wait until we receive a
97     card insertion event.
98     
99 ======================================================================*/
100
101 static int avmcs_probe(struct pcmcia_device *p_dev)
102 {
103     local_info_t *local;
104
105     /* The io structure describes IO port mapping */
106     p_dev->io.NumPorts1 = 16;
107     p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
108     p_dev->io.NumPorts2 = 0;
109
110     /* Interrupt setup */
111     p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
112
113     /* General socket configuration */
114     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
115     p_dev->conf.IntType = INT_MEMORY_AND_IO;
116     p_dev->conf.ConfigIndex = 1;
117     p_dev->conf.Present = PRESENT_OPTION;
118
119     /* Allocate space for private device-specific data */
120     local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
121     if (!local)
122         goto err;
123     p_dev->priv = local;
124
125     return avmcs_config(p_dev);
126
127  err:
128     return -ENOMEM;
129 } /* avmcs_attach */
130
131 /*======================================================================
132
133     This deletes a driver "instance".  The device is de-registered
134     with Card Services.  If it has been released, all local data
135     structures are freed.  Otherwise, the structures will be freed
136     when the device is released.
137
138 ======================================================================*/
139
140 static void avmcs_detach(struct pcmcia_device *link)
141 {
142         avmcs_release(link);
143         kfree(link->priv);
144 } /* avmcs_detach */
145
146 /*======================================================================
147
148     avmcs_config() is scheduled to run after a CARD_INSERTION event
149     is received, to configure the PCMCIA socket, and to make the
150     ethernet device available to the system.
151     
152 ======================================================================*/
153
154 static int avmcs_configcheck(struct pcmcia_device *p_dev,
155                              cistpl_cftable_entry_t *cf,
156                              cistpl_cftable_entry_t *dflt,
157                              unsigned int vcc,
158                              void *priv_data)
159 {
160         if (cf->io.nwin <= 0)
161                 return -ENODEV;
162
163         p_dev->io.BasePort1 = cf->io.win[0].base;
164         p_dev->io.NumPorts1 = cf->io.win[0].len;
165         p_dev->io.NumPorts2 = 0;
166         printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
167                p_dev->io.BasePort1,
168                p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
169         return pcmcia_request_io(p_dev, &p_dev->io);
170 }
171
172 static int avmcs_config(struct pcmcia_device *link)
173 {
174     local_info_t *dev;
175     int i;
176     char devname[128];
177     int cardtype;
178     int (*addcard)(unsigned int port, unsigned irq);
179
180     dev = link->priv;
181
182     devname[0] = 0;
183     if (link->prod_id[1])
184             strlcpy(devname, link->prod_id[1], sizeof(devname));
185
186     /*
187      * find IO port
188      */
189     if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
190             return -ENODEV;
191
192     do {
193         /*
194          * allocate an interrupt line
195          */
196         i = pcmcia_request_irq(link, &link->irq);
197         if (i != 0) {
198             /* undo */
199             pcmcia_disable_device(link);
200             break;
201         }
202
203         /*
204          * configure the PCMCIA socket
205           */
206         i = pcmcia_request_configuration(link, &link->conf);
207         if (i != 0) {
208             pcmcia_disable_device(link);
209             break;
210         }
211
212     } while (0);
213
214     /* At this point, the dev_node_t structure(s) should be
215        initialized and arranged in a linked list at link->dev. */
216
217     if (devname[0]) {
218         char *s = strrchr(devname, ' ');
219         if (!s)
220            s = devname;
221         else s++;
222         strcpy(dev->node.dev_name, s);
223         if (strcmp("M1", s) == 0) {
224            cardtype = AVM_CARDTYPE_M1;
225         } else if (strcmp("M2", s) == 0) {
226            cardtype = AVM_CARDTYPE_M2;
227         } else {
228            cardtype = AVM_CARDTYPE_B1;
229         }
230     } else {
231         strcpy(dev->node.dev_name, "b1");
232         cardtype = AVM_CARDTYPE_B1;
233     }
234
235     dev->node.major = 64;
236     dev->node.minor = 0;
237     link->dev_node = &dev->node;
238
239     /* If any step failed, release any partially configured state */
240     if (i != 0) {
241         avmcs_release(link);
242         return -ENODEV;
243     }
244
245
246     switch (cardtype) {
247         case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
248         case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
249         default:
250         case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
251     }
252     if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
253         printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
254                 dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
255         avmcs_release(link);
256         return -ENODEV;
257     }
258     dev->node.minor = i;
259     return 0;
260
261 } /* avmcs_config */
262
263 /*======================================================================
264
265     After a card is removed, avmcs_release() will unregister the net
266     device, and release the PCMCIA configuration.  If the device is
267     still open, this will be postponed until it is closed.
268     
269 ======================================================================*/
270
271 static void avmcs_release(struct pcmcia_device *link)
272 {
273         b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
274         pcmcia_disable_device(link);
275 } /* avmcs_release */
276
277
278 static struct pcmcia_device_id avmcs_ids[] = {
279         PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
280         PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
281         PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
282         PCMCIA_DEVICE_NULL
283 };
284 MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
285
286 static struct pcmcia_driver avmcs_driver = {
287         .owner  = THIS_MODULE,
288         .drv    = {
289                 .name   = "avm_cs",
290         },
291         .probe = avmcs_probe,
292         .remove = avmcs_detach,
293         .id_table = avmcs_ids,
294 };
295
296 static int __init avmcs_init(void)
297 {
298         return pcmcia_register_driver(&avmcs_driver);
299 }
300
301 static void __exit avmcs_exit(void)
302 {
303         pcmcia_unregister_driver(&avmcs_driver);
304 }
305
306 module_init(avmcs_init);
307 module_exit(avmcs_exit);