]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/isdn/hardware/avm/avm_cs.c
pcmcia: remove cs_types.h
[net-next-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/string.h>
17 #include <linux/tty.h>
18 #include <linux/serial.h>
19 #include <linux/major.h>
20 #include <asm/io.h>
21 #include <asm/system.h>
22
23 #include <pcmcia/cs.h>
24 #include <pcmcia/cistpl.h>
25 #include <pcmcia/ciscode.h>
26 #include <pcmcia/ds.h>
27 #include <pcmcia/cisreg.h>
28
29 #include <linux/skbuff.h>
30 #include <linux/capi.h>
31 #include <linux/b1lli.h>
32 #include <linux/b1pcmcia.h>
33
34 /*====================================================================*/
35
36 MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
37 MODULE_AUTHOR("Carsten Paeth");
38 MODULE_LICENSE("GPL");
39
40 /*====================================================================*/
41
42 /*
43    The event() function is this driver's Card Services event handler.
44    It will be called by Card Services when an appropriate card status
45    event is received.  The config() and release() entry points are
46    used to configure or release a socket, in response to card insertion
47    and ejection events.  They are invoked from the skeleton event
48    handler.
49 */
50
51 static int avmcs_config(struct pcmcia_device *link);
52 static void avmcs_release(struct pcmcia_device *link);
53
54 /*
55    The attach() and detach() entry points are used to create and destroy
56    "instances" of the driver, where each instance represents everything
57    needed to manage one actual PCMCIA card.
58 */
59
60 static void avmcs_detach(struct pcmcia_device *p_dev);
61
62 /*======================================================================
63
64     avmcs_attach() creates an "instance" of the driver, allocating
65     local data structures for one device.  The device is registered
66     with Card Services.
67
68     The dev_link structure is initialized, but we don't actually
69     configure the card at this point -- we wait until we receive a
70     card insertion event.
71     
72 ======================================================================*/
73
74 static int avmcs_probe(struct pcmcia_device *p_dev)
75 {
76
77     /* The io structure describes IO port mapping */
78     p_dev->io.NumPorts1 = 16;
79     p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
80     p_dev->io.NumPorts2 = 0;
81
82     /* General socket configuration */
83     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
84     p_dev->conf.IntType = INT_MEMORY_AND_IO;
85     p_dev->conf.ConfigIndex = 1;
86     p_dev->conf.Present = PRESENT_OPTION;
87
88     return avmcs_config(p_dev);
89 } /* avmcs_attach */
90
91 /*======================================================================
92
93     This deletes a driver "instance".  The device is de-registered
94     with Card Services.  If it has been released, all local data
95     structures are freed.  Otherwise, the structures will be freed
96     when the device is released.
97
98 ======================================================================*/
99
100 static void avmcs_detach(struct pcmcia_device *link)
101 {
102         avmcs_release(link);
103 } /* avmcs_detach */
104
105 /*======================================================================
106
107     avmcs_config() is scheduled to run after a CARD_INSERTION event
108     is received, to configure the PCMCIA socket, and to make the
109     ethernet device available to the system.
110     
111 ======================================================================*/
112
113 static int avmcs_configcheck(struct pcmcia_device *p_dev,
114                              cistpl_cftable_entry_t *cf,
115                              cistpl_cftable_entry_t *dflt,
116                              unsigned int vcc,
117                              void *priv_data)
118 {
119         if (cf->io.nwin <= 0)
120                 return -ENODEV;
121
122         p_dev->io.BasePort1 = cf->io.win[0].base;
123         p_dev->io.NumPorts1 = cf->io.win[0].len;
124         p_dev->io.NumPorts2 = 0;
125         printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
126                p_dev->io.BasePort1,
127                p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
128         return pcmcia_request_io(p_dev, &p_dev->io);
129 }
130
131 static int avmcs_config(struct pcmcia_device *link)
132 {
133     int i = -1;
134     char devname[128];
135     int cardtype;
136     int (*addcard)(unsigned int port, unsigned irq);
137
138     devname[0] = 0;
139     if (link->prod_id[1])
140             strlcpy(devname, link->prod_id[1], sizeof(devname));
141
142     /*
143      * find IO port
144      */
145     if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
146             return -ENODEV;
147
148     do {
149         if (!link->irq) {
150             /* undo */
151             pcmcia_disable_device(link);
152             break;
153         }
154
155         /*
156          * configure the PCMCIA socket
157           */
158         i = pcmcia_request_configuration(link, &link->conf);
159         if (i != 0) {
160             pcmcia_disable_device(link);
161             break;
162         }
163
164     } while (0);
165
166     if (devname[0]) {
167         char *s = strrchr(devname, ' ');
168         if (!s)
169            s = devname;
170         else s++;
171         if (strcmp("M1", s) == 0) {
172            cardtype = AVM_CARDTYPE_M1;
173         } else if (strcmp("M2", s) == 0) {
174            cardtype = AVM_CARDTYPE_M2;
175         } else {
176            cardtype = AVM_CARDTYPE_B1;
177         }
178     } else
179         cardtype = AVM_CARDTYPE_B1;
180
181     /* If any step failed, release any partially configured state */
182     if (i != 0) {
183         avmcs_release(link);
184         return -ENODEV;
185     }
186
187
188     switch (cardtype) {
189         case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
190         case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
191         default:
192         case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
193     }
194     if ((i = (*addcard)(link->io.BasePort1, link->irq)) < 0) {
195             dev_err(&link->dev, "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
196                     link->io.BasePort1, link->irq);
197             avmcs_release(link);
198             return -ENODEV;
199     }
200     return 0;
201
202 } /* avmcs_config */
203
204 /*======================================================================
205
206     After a card is removed, avmcs_release() will unregister the net
207     device, and release the PCMCIA configuration.  If the device is
208     still open, this will be postponed until it is closed.
209     
210 ======================================================================*/
211
212 static void avmcs_release(struct pcmcia_device *link)
213 {
214         b1pcmcia_delcard(link->io.BasePort1, link->irq);
215         pcmcia_disable_device(link);
216 } /* avmcs_release */
217
218
219 static struct pcmcia_device_id avmcs_ids[] = {
220         PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
221         PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
222         PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
223         PCMCIA_DEVICE_NULL
224 };
225 MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
226
227 static struct pcmcia_driver avmcs_driver = {
228         .owner  = THIS_MODULE,
229         .drv    = {
230                 .name   = "avm_cs",
231         },
232         .probe = avmcs_probe,
233         .remove = avmcs_detach,
234         .id_table = avmcs_ids,
235 };
236
237 static int __init avmcs_init(void)
238 {
239         return pcmcia_register_driver(&avmcs_driver);
240 }
241
242 static void __exit avmcs_exit(void)
243 {
244         pcmcia_unregister_driver(&avmcs_driver);
245 }
246
247 module_init(avmcs_init);
248 module_exit(avmcs_exit);