blob: 94263c22b8746965109cc6b1654a8a30df2355fd [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;
88 p_dev->conf.IntType = INT_MEMORY_AND_IO;
89 p_dev->conf.ConfigIndex = 1;
90 p_dev->conf.Present = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020092 return avma1cs_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093} /* avma1cs_attach */
94
95/*======================================================================
96
97 This deletes a driver "instance". The device is de-registered
98 with Card Services. If it has been released, all local data
99 structures are freed. Otherwise, the structures will be freed
100 when the device is released.
101
102======================================================================*/
103
Hennea4658702010-03-25 12:05:31 +0000104static void __devexit avma1cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200106 dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100107 avma1cs_release(link);
108 kfree(link->priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109} /* avma1cs_detach */
110
111/*======================================================================
112
113 avma1cs_config() is scheduled to run after a CARD_INSERTION event
114 is received, to configure the PCMCIA socket, and to make the
115 ethernet device available to the system.
116
117======================================================================*/
118
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200119static int avma1cs_configcheck(struct pcmcia_device *p_dev,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200120 cistpl_cftable_entry_t *cf,
121 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200122 unsigned int vcc,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200123 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200125 if (cf->io.nwin <= 0)
126 return -ENODEV;
127
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200128 p_dev->resource[0]->start = cf->io.win[0].base;
129 p_dev->resource[0]->end = cf->io.win[0].len;
130 p_dev->io_lines = 5;
131 return pcmcia_request_io(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Hennea4658702010-03-25 12:05:31 +0000135static int __devinit avma1cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Dominik Brodowskieb141202010-03-07 12:21:16 +0100137 int i = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 char devname[128];
139 IsdnCard_t icard;
140 int busy = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200141
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200142 dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200144 devname[0] = 0;
145 if (link->prod_id[1])
146 strlcpy(devname, link->prod_id[1], sizeof(devname));
147
148 if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
149 return -ENODEV;
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 /*
153 * allocate an interrupt line
154 */
Dominik Brodowskieb141202010-03-07 12:21:16 +0100155 if (!link->irq) {
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100156 /* undo */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200157 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 break;
159 }
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 /*
162 * configure the PCMCIA socket
163 */
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200164 i = pcmcia_request_configuration(link, &link->conf);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200165 if (i != 0) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200166 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 break;
168 }
169
170 } while (0);
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 /* If any step failed, release any partially configured state */
173 if (i != 0) {
174 avma1cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200175 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 }
177
178 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200179 (unsigned int) link->resource[0]->start, link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Dominik Brodowskieb141202010-03-07 12:21:16 +0100181 icard.para[0] = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200182 icard.para[1] = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 icard.protocol = isdnprot;
184 icard.typ = ISDN_CTYPE_A1_PCMCIA;
185
186 i = hisax_init_pcmcia(link, &busy, &icard);
187 if (i < 0) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200188 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
189 "PCMCIA %d at i/o %#x\n", i,
190 (unsigned int) link->resource[0]->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 avma1cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200192 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 }
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100194 link->priv = (void *) (unsigned long) i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200196 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197} /* avma1cs_config */
198
199/*======================================================================
200
201 After a card is removed, avma1cs_release() will unregister the net
202 device, and release the PCMCIA configuration. If the device is
203 still open, this will be postponed until it is closed.
204
205======================================================================*/
206
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200207static void avma1cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100209 unsigned long minor = (unsigned long) link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200211 dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100213 /* now unregister function with hisax */
Dominik Brodowskib498ada2010-03-20 19:43:26 +0100214 HiSax_closecard(minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200216 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217} /* avma1cs_release */
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Dominik Brodowskic594c122005-06-27 16:28:34 -0700220static struct pcmcia_device_id avma1cs_ids[] = {
221 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
222 PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
223 PCMCIA_DEVICE_NULL
224};
225MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227static struct pcmcia_driver avma1cs_driver = {
228 .owner = THIS_MODULE,
229 .drv = {
230 .name = "avma1_cs",
231 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200232 .probe = avma1cs_probe,
Hennea4658702010-03-25 12:05:31 +0000233 .remove = __devexit_p(avma1cs_detach),
Dominik Brodowskic594c122005-06-27 16:28:34 -0700234 .id_table = avma1cs_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235};
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237/*====================================================================*/
238
239static int __init init_avma1_cs(void)
240{
241 return(pcmcia_register_driver(&avma1cs_driver));
242}
243
244static void __exit exit_avma1_cs(void)
245{
246 pcmcia_unregister_driver(&avma1cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
249module_init(init_avma1_cs);
250module_exit(exit_avma1_cs);