blob: 7d5ff20b5d5b45de57410f38f74778912fb793da [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
3 *
4 * Author Carsten Paeth
5 * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.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
14
15#include <linux/kernel.h>
16#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/ptrace.h>
18#include <linux/slab.h>
19#include <linux/string.h>
20#include <asm/io.h>
21#include <asm/system.h>
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <pcmcia/cs.h>
24#include <pcmcia/cistpl.h>
25#include <pcmcia/ds.h>
26#include "hisax_cfg.h"
27
28MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
29MODULE_AUTHOR("Carsten Paeth");
30MODULE_LICENSE("GPL");
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33/*====================================================================*/
34
35/* Parameters that can be set with 'insmod' */
36
37static int isdnprot = 2;
38
39module_param(isdnprot, int, 0);
40
41/*====================================================================*/
42
43/*
44 The event() function is this driver's Card Services event handler.
45 It will be called by Card Services when an appropriate card status
46 event is received. The config() and release() entry points are
47 used to configure or release a socket, in response to card insertion
48 and ejection events. They are invoked from the skeleton event
49 handler.
50*/
51
Hennea4658702010-03-25 12:05:31 +000052static int avma1cs_config(struct pcmcia_device *link) __devinit ;
Dominik Brodowskifba395e2006-03-31 17:21:06 +020053static void avma1cs_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/*
56 The attach() and detach() entry points are used to create and destroy
57 "instances" of the driver, where each instance represents everything
58 needed to manage one actual PCMCIA card.
59*/
60
Hennea4658702010-03-25 12:05:31 +000061static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Linus Torvalds1da177e2005-04-16 15:20:36 -070064/*======================================================================
65
66 avma1cs_attach() creates an "instance" of the driver, allocating
67 local data structures for one device. The device is registered
68 with Card Services.
69
70 The dev_link structure is initialized, but we don't actually
71 configure the card at this point -- we wait until we receive a
72 card insertion event.
73
74======================================================================*/
75
Hennea4658702010-03-25 12:05:31 +000076static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020078 dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 /* The io structure describes IO port mapping */
Dominik Brodowski90abdc32010-07-24 17:23:51 +020081 p_dev->resource[0]->end = 16;
82 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
83 p_dev->resource[1]->end = 16;
84 p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 /* General socket configuration */
Dominik Brodowskifd238232006-03-05 10:45:09 +010087 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
Dominik Brodowskifd238232006-03-05 10:45:09 +010088 p_dev->conf.ConfigIndex = 1;
89 p_dev->conf.Present = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020091 return avma1cs_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092} /* avma1cs_attach */
93
94/*======================================================================
95
96 This deletes a driver "instance". The device is de-registered
97 with Card Services. If it has been released, all local data
98 structures are freed. Otherwise, the structures will be freed
99 when the device is released.
100
101======================================================================*/
102
Hennea4658702010-03-25 12:05:31 +0000103static void __devexit avma1cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200105 dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100106 avma1cs_release(link);
107 kfree(link->priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108} /* avma1cs_detach */
109
110/*======================================================================
111
112 avma1cs_config() is scheduled to run after a CARD_INSERTION event
113 is received, to configure the PCMCIA socket, and to make the
114 ethernet device available to the system.
115
116======================================================================*/
117
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200118static int avma1cs_configcheck(struct pcmcia_device *p_dev,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200119 cistpl_cftable_entry_t *cf,
120 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200121 unsigned int vcc,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200122 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200124 if (cf->io.nwin <= 0)
125 return -ENODEV;
126
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200127 p_dev->resource[0]->start = cf->io.win[0].base;
128 p_dev->resource[0]->end = cf->io.win[0].len;
129 p_dev->io_lines = 5;
130 return pcmcia_request_io(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Hennea4658702010-03-25 12:05:31 +0000134static int __devinit avma1cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Dominik Brodowskieb141202010-03-07 12:21:16 +0100136 int i = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 char devname[128];
138 IsdnCard_t icard;
139 int busy = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200140
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200141 dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200143 devname[0] = 0;
144 if (link->prod_id[1])
145 strlcpy(devname, link->prod_id[1], sizeof(devname));
146
147 if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
148 return -ENODEV;
149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 /*
152 * allocate an interrupt line
153 */
Dominik Brodowskieb141202010-03-07 12:21:16 +0100154 if (!link->irq) {
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100155 /* undo */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200156 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 break;
158 }
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 /*
161 * configure the PCMCIA socket
162 */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200163 i = pcmcia_request_configuration(link, &link->conf);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200164 if (i != 0) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200165 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 break;
167 }
168
169 } while (0);
170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 /* If any step failed, release any partially configured state */
172 if (i != 0) {
173 avma1cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200174 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
176
177 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200178 (unsigned int) link->resource[0]->start, link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Dominik Brodowskieb141202010-03-07 12:21:16 +0100180 icard.para[0] = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200181 icard.para[1] = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 icard.protocol = isdnprot;
183 icard.typ = ISDN_CTYPE_A1_PCMCIA;
184
185 i = hisax_init_pcmcia(link, &busy, &icard);
186 if (i < 0) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200187 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
188 "PCMCIA %d at i/o %#x\n", i,
189 (unsigned int) link->resource[0]->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 avma1cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200191 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100193 link->priv = (void *) (unsigned long) i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200195 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196} /* avma1cs_config */
197
198/*======================================================================
199
200 After a card is removed, avma1cs_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 avma1cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100208 unsigned long minor = (unsigned long) link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200210 dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100212 /* now unregister function with hisax */
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100213 HiSax_closecard(minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200215 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216} /* avma1cs_release */
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Dominik Brodowskic594c122005-06-27 16:28:34 -0700219static struct pcmcia_device_id avma1cs_ids[] = {
220 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
221 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
222 PCMCIA_DEVICE_NULL
223};
224MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226static struct pcmcia_driver avma1cs_driver = {
227 .owner = THIS_MODULE,
228 .drv = {
229 .name = "avma1_cs",
230 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200231 .probe = avma1cs_probe,
Hennea4658702010-03-25 12:05:31 +0000232 .remove = __devexit_p(avma1cs_detach),
Dominik Brodowskic594c122005-06-27 16:28:34 -0700233 .id_table = avma1cs_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234};
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236/*====================================================================*/
237
238static int __init init_avma1_cs(void)
239{
240 return(pcmcia_register_driver(&avma1cs_driver));
241}
242
243static void __exit exit_avma1_cs(void)
244{
245 pcmcia_unregister_driver(&avma1cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
248module_init(init_avma1_cs);
249module_exit(exit_avma1_cs);