blob: 88899638f8358cd25c2e0f3391691e375e7073db [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 Brodowskifd238232006-03-05 10:45:09 +010081 p_dev->io.NumPorts1 = 16;
82 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
83 p_dev->io.NumPorts2 = 16;
84 p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
85 p_dev->io.IOAddrLines = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 /* General socket configuration */
Dominik Brodowskifd238232006-03-05 10:45:09 +010088 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
89 p_dev->conf.IntType = INT_MEMORY_AND_IO;
90 p_dev->conf.ConfigIndex = 1;
91 p_dev->conf.Present = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020093 return avma1cs_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094} /* avma1cs_attach */
95
96/*======================================================================
97
98 This deletes a driver "instance". The device is de-registered
99 with Card Services. If it has been released, all local data
100 structures are freed. Otherwise, the structures will be freed
101 when the device is released.
102
103======================================================================*/
104
Hennea4658702010-03-25 12:05:31 +0000105static void __devexit avma1cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200107 dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100108 avma1cs_release(link);
109 kfree(link->priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110} /* avma1cs_detach */
111
112/*======================================================================
113
114 avma1cs_config() is scheduled to run after a CARD_INSERTION event
115 is received, to configure the PCMCIA socket, and to make the
116 ethernet device available to the system.
117
118======================================================================*/
119
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200120static int avma1cs_configcheck(struct pcmcia_device *p_dev,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200121 cistpl_cftable_entry_t *cf,
122 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200123 unsigned int vcc,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200124 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200126 if (cf->io.nwin <= 0)
127 return -ENODEV;
128
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200129 p_dev->io.BasePort1 = cf->io.win[0].base;
130 p_dev->io.NumPorts1 = cf->io.win[0].len;
131 p_dev->io.NumPorts2 = 0;
132 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
133 p_dev->io.BasePort1,
134 p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
135 return pcmcia_request_io(p_dev, &p_dev->io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Hennea4658702010-03-25 12:05:31 +0000139static int __devinit avma1cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
Dominik Brodowskieb141202010-03-07 12:21:16 +0100141 int i = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 char devname[128];
143 IsdnCard_t icard;
144 int busy = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200145
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200146 dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200148 devname[0] = 0;
149 if (link->prod_id[1])
150 strlcpy(devname, link->prod_id[1], sizeof(devname));
151
152 if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
153 return -ENODEV;
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 /*
157 * allocate an interrupt line
158 */
Dominik Brodowskieb141202010-03-07 12:21:16 +0100159 if (!link->irq) {
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100160 /* undo */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200161 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 break;
163 }
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 /*
166 * configure the PCMCIA socket
167 */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200168 i = pcmcia_request_configuration(link, &link->conf);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200169 if (i != 0) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200170 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 break;
172 }
173
174 } while (0);
175
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 /* If any step failed, release any partially configured state */
177 if (i != 0) {
178 avma1cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200179 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181
182 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200183 (unsigned int) link->resource[0]->start, link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Dominik Brodowskieb141202010-03-07 12:21:16 +0100185 icard.para[0] = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200186 icard.para[1] = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 icard.protocol = isdnprot;
188 icard.typ = ISDN_CTYPE_A1_PCMCIA;
189
190 i = hisax_init_pcmcia(link, &busy, &icard);
191 if (i < 0) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200192 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
193 "PCMCIA %d at i/o %#x\n", i,
194 (unsigned int) link->resource[0]->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 avma1cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200196 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100198 link->priv = (void *) (unsigned long) i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200200 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201} /* avma1cs_config */
202
203/*======================================================================
204
205 After a card is removed, avma1cs_release() will unregister the net
206 device, and release the PCMCIA configuration. If the device is
207 still open, this will be postponed until it is closed.
208
209======================================================================*/
210
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200211static void avma1cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100213 unsigned long minor = (unsigned long) link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200215 dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100217 /* now unregister function with hisax */
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100218 HiSax_closecard(minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200220 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221} /* avma1cs_release */
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Dominik Brodowskic594c122005-06-27 16:28:34 -0700224static struct pcmcia_device_id avma1cs_ids[] = {
225 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
226 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
227 PCMCIA_DEVICE_NULL
228};
229MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static struct pcmcia_driver avma1cs_driver = {
232 .owner = THIS_MODULE,
233 .drv = {
234 .name = "avma1_cs",
235 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200236 .probe = avma1cs_probe,
Hennea4658702010-03-25 12:05:31 +0000237 .remove = __devexit_p(avma1cs_detach),
Dominik Brodowskic594c122005-06-27 16:28:34 -0700238 .id_table = avma1cs_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239};
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241/*====================================================================*/
242
243static int __init init_avma1_cs(void)
244{
245 return(pcmcia_register_driver(&avma1cs_driver));
246}
247
248static void __exit exit_avma1_cs(void)
249{
250 pcmcia_unregister_driver(&avma1cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
252
253module_init(init_avma1_cs);
254module_exit(exit_avma1_cs);