blob: ebe56918f6fc5e0bbd52d2a4ca6231c41cd83fc1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
Joe Perches475be4d2012-02-19 19:52:38 -08003 An elsa_cs PCMCIA client driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
Joe Perches475be4d2012-02-19 19:52:38 -08005 This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7
Joe Perches475be4d2012-02-19 19:52:38 -08008 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/
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Joe Perches475be4d2012-02-19 19:52:38 -080013 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Joe Perches475be4d2012-02-19 19:52:38 -080018 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Joe Perches475be4d2012-02-19 19:52:38 -080022 Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
23 Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Joe Perches475be4d2012-02-19 19:52:38 -080025 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Joe Perches475be4d2012-02-19 19:52:38 -080036 ======================================================================*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <pcmcia/cistpl.h>
49#include <pcmcia/cisreg.h>
50#include <pcmcia/ds.h>
51#include "hisax_cfg.h"
52
53MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
54MODULE_AUTHOR("Klaus Lichtenwalder");
55MODULE_LICENSE("Dual MPL/GPL");
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58/*====================================================================*/
59
60/* Parameters that can be set with 'insmod' */
61
62static int protocol = 2; /* EURO-ISDN Default */
63module_param(protocol, int, 0);
64
Greg Kroah-Hartmaned5a84c2012-12-21 13:13:05 -080065static int elsa_cs_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020066static void elsa_cs_release(struct pcmcia_device *link);
Greg Kroah-Hartmaned5a84c2012-12-21 13:13:05 -080067static void elsa_cs_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Linus Torvalds1da177e2005-04-16 15:20:36 -070069typedef struct local_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010070 struct pcmcia_device *p_dev;
Joe Perches475be4d2012-02-19 19:52:38 -080071 int busy;
72 int cardnr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073} local_info_t;
74
Greg Kroah-Hartmaned5a84c2012-12-21 13:13:05 -080075static int elsa_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
Joe Perches475be4d2012-02-19 19:52:38 -080077 local_info_t *local;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Joe Perches475be4d2012-02-19 19:52:38 -080079 dev_dbg(&link->dev, "elsa_cs_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Joe Perches475be4d2012-02-19 19:52:38 -080081 /* Allocate space for private device-specific data */
82 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
83 if (!local) return -ENOMEM;
Dominik Brodowskifd238232006-03-05 10:45:09 +010084
Joe Perches475be4d2012-02-19 19:52:38 -080085 local->p_dev = link;
86 link->priv = local;
Dominik Brodowskifd238232006-03-05 10:45:09 +010087
Joe Perches475be4d2012-02-19 19:52:38 -080088 local->cardnr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Joe Perches475be4d2012-02-19 19:52:38 -080090 return elsa_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091} /* elsa_cs_attach */
92
Greg Kroah-Hartmaned5a84c2012-12-21 13:13:05 -080093static void elsa_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
Dominik Brodowskie2d40962006-03-02 00:09:29 +010095 local_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020097 dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Dominik Brodowskie2d40962006-03-02 00:09:29 +010099 info->busy = 1;
100 elsa_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100102 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103} /* elsa_cs_detach */
104
Dominik Brodowski00990e72010-07-30 13:13:46 +0200105static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200107 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200109 p_dev->io_lines = 3;
Dominik Brodowski00990e72010-07-30 13:13:46 +0200110 p_dev->resource[0]->end = 8;
111 p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
112 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200113
Dominik Brodowski00990e72010-07-30 13:13:46 +0200114 if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200115 printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200116 if (!pcmcia_request_io(p_dev))
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200117 return 0;
118 } else {
119 printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200120 for (j = 0x2f0; j > 0x100; j -= 0x10) {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200121 p_dev->resource[0]->start = j;
122 if (!pcmcia_request_io(p_dev))
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200123 return 0;
124 }
125 }
126 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
Greg Kroah-Hartmaned5a84c2012-12-21 13:13:05 -0800129static int elsa_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Joe Perches475be4d2012-02-19 19:52:38 -0800131 int i;
132 IsdnCard_t icard;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Joe Perches475be4d2012-02-19 19:52:38 -0800134 dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Joe Perches475be4d2012-02-19 19:52:38 -0800136 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
Dominik Brodowski00990e72010-07-30 13:13:46 +0200137
Joe Perches475be4d2012-02-19 19:52:38 -0800138 i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
139 if (i != 0)
140 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Joe Perches475be4d2012-02-19 19:52:38 -0800142 if (!link->irq)
143 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Joe Perches475be4d2012-02-19 19:52:38 -0800145 i = pcmcia_enable_device(link);
146 if (i != 0)
147 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Joe Perches475be4d2012-02-19 19:52:38 -0800149 icard.para[0] = link->irq;
150 icard.para[1] = link->resource[0]->start;
151 icard.protocol = protocol;
152 icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Joe Perches475be4d2012-02-19 19:52:38 -0800154 i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
155 if (i < 0) {
156 printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
157 "PCMCIA %d with %pR\n", i, link->resource[0]);
158 elsa_cs_release(link);
159 } else
160 ((local_info_t *)link->priv)->cardnr = i;
161
162 return 0;
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200163failed:
Joe Perches475be4d2012-02-19 19:52:38 -0800164 elsa_cs_release(link);
165 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166} /* elsa_cs_config */
167
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200168static void elsa_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
Joe Perches475be4d2012-02-19 19:52:38 -0800170 local_info_t *local = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Joe Perches475be4d2012-02-19 19:52:38 -0800172 dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Joe Perches475be4d2012-02-19 19:52:38 -0800174 if (local) {
175 if (local->cardnr >= 0) {
176 /* no unregister function with hisax */
177 HiSax_closecard(local->cardnr);
178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Joe Perches475be4d2012-02-19 19:52:38 -0800181 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182} /* elsa_cs_release */
183
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200184static int elsa_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100185{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100186 local_info_t *dev = link->priv;
187
Joe Perches475be4d2012-02-19 19:52:38 -0800188 dev->busy = 1;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100189
190 return 0;
191}
192
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200193static int elsa_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100194{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100195 local_info_t *dev = link->priv;
196
Joe Perches475be4d2012-02-19 19:52:38 -0800197 dev->busy = 0;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100198
199 return 0;
200}
201
Joe Perches25f8f542011-05-03 19:29:01 -0700202static const struct pcmcia_device_id elsa_ids[] = {
Dominik Brodowski02ae38c2005-06-27 16:28:39 -0700203 PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
204 PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
205 PCMCIA_DEVICE_NULL
206};
207MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static struct pcmcia_driver elsa_cs_driver = {
210 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200211 .name = "elsa_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200212 .probe = elsa_cs_probe,
Greg Kroah-Hartmaned5a84c2012-12-21 13:13:05 -0800213 .remove = elsa_cs_detach,
Dominik Brodowski02ae38c2005-06-27 16:28:39 -0700214 .id_table = elsa_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100215 .suspend = elsa_suspend,
216 .resume = elsa_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217};
218
219static int __init init_elsa_cs(void)
220{
221 return pcmcia_register_driver(&elsa_cs_driver);
222}
223
224static void __exit exit_elsa_cs(void)
225{
226 pcmcia_unregister_driver(&elsa_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
229module_init(init_elsa_cs);
230module_exit(exit_elsa_cs);