blob: 9dbab9c99beabed2ca18f00a3886f6005d563a08 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#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
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <pcmcia/cistpl.h>
24#include <pcmcia/ciscode.h>
25#include <pcmcia/ds.h>
26#include <pcmcia/cisreg.h>
27
28#include <linux/skbuff.h>
29#include <linux/capi.h>
30#include <linux/b1lli.h>
31#include <linux/b1pcmcia.h>
32
33/*====================================================================*/
34
35MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
36MODULE_AUTHOR("Carsten Paeth");
37MODULE_LICENSE("GPL");
38
39/*====================================================================*/
40
41/*
42 The event() function is this driver's Card Services event handler.
43 It will be called by Card Services when an appropriate card status
44 event is received. The config() and release() entry points are
45 used to configure or release a socket, in response to card insertion
46 and ejection events. They are invoked from the skeleton event
47 handler.
48*/
49
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020050static int avmcs_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020051static void avmcs_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53/*
54 The attach() and detach() entry points are used to create and destroy
55 "instances" of the driver, where each instance represents everything
56 needed to manage one actual PCMCIA card.
57*/
58
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010059static void avmcs_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Linus Torvalds1da177e2005-04-16 15:20:36 -070061/*======================================================================
62
63 avmcs_attach() creates an "instance" of the driver, allocating
64 local data structures for one device. The device is registered
65 with Card Services.
66
67 The dev_link structure is initialized, but we don't actually
68 configure the card at this point -- we wait until we receive a
69 card insertion event.
70
71======================================================================*/
72
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020073static int avmcs_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010075
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 /* The io structure describes IO port mapping */
Dominik Brodowski90abdc32010-07-24 17:23:51 +020077 p_dev->resource[0]->end = 16;
78 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 /* General socket configuration */
Dominik Brodowski1ac71e52010-07-29 19:27:09 +020081 p_dev->config_flags |= CONF_ENABLE_IRQ;
Dominik Brodowski7feabb62010-07-29 18:35:47 +020082 p_dev->config_index = 1;
83 p_dev->config_regs = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020085 return avmcs_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086} /* avmcs_attach */
87
88/*======================================================================
89
90 This deletes a driver "instance". The device is de-registered
91 with Card Services. If it has been released, all local data
92 structures are freed. Otherwise, the structures will be freed
93 when the device is released.
94
95======================================================================*/
96
Dominik Brodowskifba395e2006-03-31 17:21:06 +020097static void avmcs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010099 avmcs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100} /* avmcs_detach */
101
102/*======================================================================
103
104 avmcs_config() is scheduled to run after a CARD_INSERTION event
105 is received, to configure the PCMCIA socket, and to make the
106 ethernet device available to the system.
107
108======================================================================*/
109
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200110static int avmcs_configcheck(struct pcmcia_device *p_dev,
111 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200112 cistpl_cftable_entry_t *dflt,
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200113 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200115 if (cf->io.nwin <= 0)
116 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200118 p_dev->resource[0]->start = cf->io.win[0].base;
119 p_dev->resource[0]->end = cf->io.win[0].len;
120 return pcmcia_request_io(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121}
122
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200123static int avmcs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124{
Dominik Brodowskieb141202010-03-07 12:21:16 +0100125 int i = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 char devname[128];
127 int cardtype;
128 int (*addcard)(unsigned int port, unsigned irq);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200129
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200130 devname[0] = 0;
131 if (link->prod_id[1])
132 strlcpy(devname, link->prod_id[1], sizeof(devname));
133
134 /*
135 * find IO port
136 */
137 if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
138 return -ENODEV;
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 do {
Dominik Brodowskieb141202010-03-07 12:21:16 +0100141 if (!link->irq) {
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100142 /* undo */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200143 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 break;
145 }
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 /*
148 * configure the PCMCIA socket
149 */
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200150 i = pcmcia_enable_device(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200151 if (i != 0) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200152 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 break;
154 }
155
156 } while (0);
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (devname[0]) {
159 char *s = strrchr(devname, ' ');
160 if (!s)
161 s = devname;
162 else s++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 if (strcmp("M1", s) == 0) {
164 cardtype = AVM_CARDTYPE_M1;
165 } else if (strcmp("M2", s) == 0) {
166 cardtype = AVM_CARDTYPE_M2;
167 } else {
168 cardtype = AVM_CARDTYPE_B1;
169 }
Dominik Brodowskided6a1a2010-03-20 19:35:12 +0100170 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 cardtype = AVM_CARDTYPE_B1;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 /* If any step failed, release any partially configured state */
174 if (i != 0) {
175 avmcs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200176 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 }
178
179
180 switch (cardtype) {
181 case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
182 case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
183 default:
184 case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
185 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200186 if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) {
187 dev_err(&link->dev,
188 "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
189 (unsigned int) link->resource[0]->start, link->irq);
Dominik Brodowskided6a1a2010-03-20 19:35:12 +0100190 avmcs_release(link);
191 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200193 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195} /* avmcs_config */
196
197/*======================================================================
198
199 After a card is removed, avmcs_release() will unregister the net
200 device, and release the PCMCIA configuration. If the device is
201 still open, this will be postponed until it is closed.
202
203======================================================================*/
204
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200205static void avmcs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200207 b1pcmcia_delcard(link->resource[0]->start, link->irq);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200208 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209} /* avmcs_release */
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Dominik Brodowskia13bcf02005-06-27 16:28:35 -0700212static struct pcmcia_device_id avmcs_ids[] = {
213 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
214 PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
215 PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
216 PCMCIA_DEVICE_NULL
217};
218MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static struct pcmcia_driver avmcs_driver = {
221 .owner = THIS_MODULE,
222 .drv = {
223 .name = "avm_cs",
224 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200225 .probe = avmcs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100226 .remove = avmcs_detach,
Dominik Brodowskia13bcf02005-06-27 16:28:35 -0700227 .id_table = avmcs_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
230static int __init avmcs_init(void)
231{
232 return pcmcia_register_driver(&avmcs_driver);
233}
234
235static void __exit avmcs_exit(void)
236{
237 pcmcia_unregister_driver(&avmcs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
240module_init(avmcs_init);
241module_exit(avmcs_exit);