blob: 8e4292895336481b12b585af569caffe062f472e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 An elsa_cs PCMCIA client driver
4
5 This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
6
7
8 The contents of this file are subject to the Mozilla Public
9 License Version 1.1 (the "License"); you may not use this file
10 except in compliance with the License. You may obtain a copy of
11 the License at http://www.mozilla.org/MPL/
12
13 Software distributed under the License is distributed on an "AS
14 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 rights and limitations under the License.
17
18 The initial developer of the original code is David A. Hinds
19 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
20 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21
22 Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
23 Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
24
25 Alternatively, the contents of this file may be used under the
26 terms of the GNU General Public License version 2 (the "GPL"), in
27 which case the provisions of the GPL are applicable instead of the
28 above. If you wish to allow the use of your version of this file
29 only under the terms of the GPL and not to allow others to use
30 your version of this file under the MPL, indicate your decision
31 by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL. If you do not delete
33 the provisions above, a recipient may use your version of this
34 file under either the MPL or the GPL.
35
36======================================================================*/
37
38#include <linux/module.h>
39#include <linux/kernel.h>
40#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/ptrace.h>
42#include <linux/slab.h>
43#include <linux/string.h>
44#include <linux/timer.h>
45#include <linux/ioport.h>
46#include <asm/io.h>
47#include <asm/system.h>
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <pcmcia/cistpl.h>
50#include <pcmcia/cisreg.h>
51#include <pcmcia/ds.h>
52#include "hisax_cfg.h"
53
54MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
55MODULE_AUTHOR("Klaus Lichtenwalder");
56MODULE_LICENSE("Dual MPL/GPL");
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59/*====================================================================*/
60
61/* Parameters that can be set with 'insmod' */
62
63static int protocol = 2; /* EURO-ISDN Default */
64module_param(protocol, int, 0);
65
Hennef61bb622010-03-25 12:05:32 +000066static int elsa_cs_config(struct pcmcia_device *link) __devinit ;
Dominik Brodowskifba395e2006-03-31 17:21:06 +020067static void elsa_cs_release(struct pcmcia_device *link);
Hennef61bb622010-03-25 12:05:32 +000068static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Linus Torvalds1da177e2005-04-16 15:20:36 -070070typedef struct local_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010071 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 int busy;
73 int cardnr;
74} local_info_t;
75
Hennef61bb622010-03-25 12:05:32 +000076static int __devinit elsa_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 local_info_t *local;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020080 dev_dbg(&link->dev, "elsa_cs_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82 /* Allocate space for private device-specific data */
Burman Yan41f96932006-12-08 02:39:35 -080083 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010084 if (!local) return -ENOMEM;
Dominik Brodowskifd238232006-03-05 10:45:09 +010085
Dominik Brodowskifba395e2006-03-31 17:21:06 +020086 local->p_dev = link;
Dominik Brodowskifd238232006-03-05 10:45:09 +010087 link->priv = local;
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 local->cardnr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020091 return elsa_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092} /* elsa_cs_attach */
93
Hennef61bb622010-03-25 12:05:32 +000094static void __devexit elsa_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
Dominik Brodowskie2d40962006-03-02 00:09:29 +010096 local_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020098 dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100100 info->busy = 1;
101 elsa_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100103 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104} /* elsa_cs_detach */
105
Dominik Brodowski00990e72010-07-30 13:13:46 +0200106static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200108 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200110 p_dev->io_lines = 3;
Dominik Brodowski00990e72010-07-30 13:13:46 +0200111 p_dev->resource[0]->end = 8;
112 p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
113 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200114
Dominik Brodowski00990e72010-07-30 13:13:46 +0200115 if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200116 printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200117 if (!pcmcia_request_io(p_dev))
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200118 return 0;
119 } else {
120 printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200121 for (j = 0x2f0; j > 0x100; j -= 0x10) {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200122 p_dev->resource[0]->start = j;
123 if (!pcmcia_request_io(p_dev))
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200124 return 0;
125 }
126 }
127 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
129
Hennef61bb622010-03-25 12:05:32 +0000130static int __devinit elsa_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 local_info_t *dev;
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200133 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 IsdnCard_t icard;
135
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200136 dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 dev = link->priv;
138
Dominik Brodowski00990e72010-07-30 13:13:46 +0200139 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
140
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200141 i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200142 if (i != 0)
143 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Dominik Brodowskieb141202010-03-07 12:21:16 +0100145 if (!link->irq)
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200146 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200148 i = pcmcia_enable_device(link);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200149 if (i != 0)
150 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Dominik Brodowskieb141202010-03-07 12:21:16 +0100152 icard.para[0] = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200153 icard.para[1] = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 icard.protocol = protocol;
155 icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
156
157 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
158 if (i < 0) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200159 printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
160 "PCMCIA %d with %pR\n", i, link->resource[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 elsa_cs_release(link);
162 } else
163 ((local_info_t*)link->priv)->cardnr = i;
164
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200165 return 0;
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200166failed:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 elsa_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200168 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169} /* elsa_cs_config */
170
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200171static void elsa_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
173 local_info_t *local = link->priv;
174
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200175 dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177 if (local) {
178 if (local->cardnr >= 0) {
179 /* no unregister function with hisax */
180 HiSax_closecard(local->cardnr);
181 }
182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200184 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185} /* elsa_cs_release */
186
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200187static int elsa_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100188{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100189 local_info_t *dev = link->priv;
190
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100191 dev->busy = 1;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100192
193 return 0;
194}
195
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200196static int elsa_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100197{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100198 local_info_t *dev = link->priv;
199
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100200 dev->busy = 0;
201
202 return 0;
203}
204
Joe Perches25f8f542011-05-03 19:29:01 -0700205static const struct pcmcia_device_id elsa_ids[] = {
Dominik Brodowski02ae38c2005-06-27 16:28:39 -0700206 PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
207 PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
208 PCMCIA_DEVICE_NULL
209};
210MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212static struct pcmcia_driver elsa_cs_driver = {
213 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200214 .name = "elsa_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200215 .probe = elsa_cs_probe,
Hennef61bb622010-03-25 12:05:32 +0000216 .remove = __devexit_p(elsa_cs_detach),
Dominik Brodowski02ae38c2005-06-27 16:28:39 -0700217 .id_table = elsa_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100218 .suspend = elsa_suspend,
219 .resume = elsa_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220};
221
222static int __init init_elsa_cs(void)
223{
224 return pcmcia_register_driver(&elsa_cs_driver);
225}
226
227static void __exit exit_elsa_cs(void)
228{
229 pcmcia_unregister_driver(&elsa_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232module_init(init_elsa_cs);
233module_exit(exit_elsa_cs);