blob: 6ea5cd28d3490e54c7d7361fc3f5e29be4453b97 [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 Brodowskiad913c12008-08-02 16:12:00 +0200113 unsigned int vcc,
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200114 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200116 if (cf->io.nwin <= 0)
117 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200119 p_dev->resource[0]->start = cf->io.win[0].base;
120 p_dev->resource[0]->end = cf->io.win[0].len;
121 return pcmcia_request_io(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200124static int avmcs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
Dominik Brodowskieb141202010-03-07 12:21:16 +0100126 int i = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 char devname[128];
128 int cardtype;
129 int (*addcard)(unsigned int port, unsigned irq);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200130
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200131 devname[0] = 0;
132 if (link->prod_id[1])
133 strlcpy(devname, link->prod_id[1], sizeof(devname));
134
135 /*
136 * find IO port
137 */
138 if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
139 return -ENODEV;
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 do {
Dominik Brodowskieb141202010-03-07 12:21:16 +0100142 if (!link->irq) {
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100143 /* undo */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200144 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 break;
146 }
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 /*
149 * configure the PCMCIA socket
150 */
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200151 i = pcmcia_enable_device(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200152 if (i != 0) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200153 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 break;
155 }
156
157 } while (0);
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if (devname[0]) {
160 char *s = strrchr(devname, ' ');
161 if (!s)
162 s = devname;
163 else s++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 if (strcmp("M1", s) == 0) {
165 cardtype = AVM_CARDTYPE_M1;
166 } else if (strcmp("M2", s) == 0) {
167 cardtype = AVM_CARDTYPE_M2;
168 } else {
169 cardtype = AVM_CARDTYPE_B1;
170 }
Dominik Brodowskided6a1a2010-03-20 19:35:12 +0100171 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 cardtype = AVM_CARDTYPE_B1;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 /* If any step failed, release any partially configured state */
175 if (i != 0) {
176 avmcs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200177 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 }
179
180
181 switch (cardtype) {
182 case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
183 case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
184 default:
185 case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
186 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200187 if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) {
188 dev_err(&link->dev,
189 "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
190 (unsigned int) link->resource[0]->start, link->irq);
Dominik Brodowskided6a1a2010-03-20 19:35:12 +0100191 avmcs_release(link);
192 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 }
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200194 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196} /* avmcs_config */
197
198/*======================================================================
199
200 After a card is removed, avmcs_release() will unregister the net
201 device, and release the PCMCIA configuration. If the device is
202 still open, this will be postponed until it is closed.
203
204======================================================================*/
205
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200206static void avmcs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200208 b1pcmcia_delcard(link->resource[0]->start, link->irq);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200209 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210} /* avmcs_release */
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Dominik Brodowskia13bcf02005-06-27 16:28:35 -0700213static struct pcmcia_device_id avmcs_ids[] = {
214 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
215 PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
216 PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
217 PCMCIA_DEVICE_NULL
218};
219MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static struct pcmcia_driver avmcs_driver = {
222 .owner = THIS_MODULE,
223 .drv = {
224 .name = "avm_cs",
225 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200226 .probe = avmcs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100227 .remove = avmcs_detach,
Dominik Brodowskia13bcf02005-06-27 16:28:35 -0700228 .id_table = avmcs_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229};
230
231static int __init avmcs_init(void)
232{
233 return pcmcia_register_driver(&avmcs_driver);
234}
235
236static void __exit avmcs_exit(void)
237{
238 pcmcia_unregister_driver(&avmcs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239}
240
241module_init(avmcs_init);
242module_exit(avmcs_exit);