blob: fe254e74a850de001ea8226431755dd560bbb540 [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>
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
Joe Perches475be4d2012-02-19 19:52:38 -080066static 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;
Joe Perches475be4d2012-02-19 19:52:38 -080072 int busy;
73 int cardnr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074} 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{
Joe Perches475be4d2012-02-19 19:52:38 -080078 local_info_t *local;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Joe Perches475be4d2012-02-19 19:52:38 -080080 dev_dbg(&link->dev, "elsa_cs_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Joe Perches475be4d2012-02-19 19:52:38 -080082 /* Allocate space for private device-specific data */
83 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
84 if (!local) return -ENOMEM;
Dominik Brodowskifd238232006-03-05 10:45:09 +010085
Joe Perches475be4d2012-02-19 19:52:38 -080086 local->p_dev = link;
87 link->priv = local;
Dominik Brodowskifd238232006-03-05 10:45:09 +010088
Joe Perches475be4d2012-02-19 19:52:38 -080089 local->cardnr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Joe Perches475be4d2012-02-19 19:52:38 -080091 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{
Joe Perches475be4d2012-02-19 19:52:38 -0800132 int i;
133 IsdnCard_t icard;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Joe Perches475be4d2012-02-19 19:52:38 -0800135 dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Joe Perches475be4d2012-02-19 19:52:38 -0800137 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
Dominik Brodowski00990e72010-07-30 13:13:46 +0200138
Joe Perches475be4d2012-02-19 19:52:38 -0800139 i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
140 if (i != 0)
141 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Joe Perches475be4d2012-02-19 19:52:38 -0800143 if (!link->irq)
144 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Joe Perches475be4d2012-02-19 19:52:38 -0800146 i = pcmcia_enable_device(link);
147 if (i != 0)
148 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Joe Perches475be4d2012-02-19 19:52:38 -0800150 icard.para[0] = link->irq;
151 icard.para[1] = link->resource[0]->start;
152 icard.protocol = protocol;
153 icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Joe Perches475be4d2012-02-19 19:52:38 -0800155 i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
156 if (i < 0) {
157 printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
158 "PCMCIA %d with %pR\n", i, link->resource[0]);
159 elsa_cs_release(link);
160 } else
161 ((local_info_t *)link->priv)->cardnr = i;
162
163 return 0;
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200164failed:
Joe Perches475be4d2012-02-19 19:52:38 -0800165 elsa_cs_release(link);
166 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167} /* elsa_cs_config */
168
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200169static void elsa_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170{
Joe Perches475be4d2012-02-19 19:52:38 -0800171 local_info_t *local = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Joe Perches475be4d2012-02-19 19:52:38 -0800173 dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Joe Perches475be4d2012-02-19 19:52:38 -0800175 if (local) {
176 if (local->cardnr >= 0) {
177 /* no unregister function with hisax */
178 HiSax_closecard(local->cardnr);
179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Joe Perches475be4d2012-02-19 19:52:38 -0800182 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183} /* elsa_cs_release */
184
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200185static int elsa_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100186{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100187 local_info_t *dev = link->priv;
188
Joe Perches475be4d2012-02-19 19:52:38 -0800189 dev->busy = 1;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100190
191 return 0;
192}
193
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200194static int elsa_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100195{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100196 local_info_t *dev = link->priv;
197
Joe Perches475be4d2012-02-19 19:52:38 -0800198 dev->busy = 0;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100199
200 return 0;
201}
202
Joe Perches25f8f542011-05-03 19:29:01 -0700203static const struct pcmcia_device_id elsa_ids[] = {
Dominik Brodowski02ae38c2005-06-27 16:28:39 -0700204 PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
205 PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
206 PCMCIA_DEVICE_NULL
207};
208MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static struct pcmcia_driver elsa_cs_driver = {
211 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200212 .name = "elsa_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200213 .probe = elsa_cs_probe,
Hennef61bb622010-03-25 12:05:32 +0000214 .remove = __devexit_p(elsa_cs_detach),
Dominik Brodowski02ae38c2005-06-27 16:28:39 -0700215 .id_table = elsa_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100216 .suspend = elsa_suspend,
217 .resume = elsa_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218};
219
220static int __init init_elsa_cs(void)
221{
222 return pcmcia_register_driver(&elsa_cs_driver);
223}
224
225static void __exit exit_elsa_cs(void)
226{
227 pcmcia_unregister_driver(&elsa_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228}
229
230module_init(init_elsa_cs);
231module_exit(exit_elsa_cs);