Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /*====================================================================== |
2 | ||
475be4d8 | 3 | An elsa_cs PCMCIA client driver |
1da177e4 | 4 | |
475be4d8 | 5 | This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink |
1da177e4 LT |
6 | |
7 | ||
475be4d8 JP |
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/ | |
1da177e4 | 12 | |
475be4d8 JP |
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. | |
1da177e4 | 17 | |
475be4d8 JP |
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. | |
1da177e4 | 21 | |
475be4d8 JP |
22 | Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus |
23 | Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved. | |
1da177e4 | 24 | |
475be4d8 JP |
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. | |
1da177e4 | 35 | |
475be4d8 | 36 | ======================================================================*/ |
1da177e4 LT |
37 | |
38 | #include <linux/module.h> | |
39 | #include <linux/kernel.h> | |
40 | #include <linux/init.h> | |
1da177e4 LT |
41 | #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> | |
1da177e4 | 47 | |
1da177e4 LT |
48 | #include <pcmcia/cistpl.h> |
49 | #include <pcmcia/cisreg.h> | |
50 | #include <pcmcia/ds.h> | |
51 | #include "hisax_cfg.h" | |
52 | ||
53 | MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards"); | |
54 | MODULE_AUTHOR("Klaus Lichtenwalder"); | |
55 | MODULE_LICENSE("Dual MPL/GPL"); | |
56 | ||
1da177e4 LT |
57 | |
58 | /*====================================================================*/ | |
59 | ||
60 | /* Parameters that can be set with 'insmod' */ | |
61 | ||
62 | static int protocol = 2; /* EURO-ISDN Default */ | |
63 | module_param(protocol, int, 0); | |
64 | ||
475be4d8 | 65 | static int elsa_cs_config(struct pcmcia_device *link) __devinit; |
fba395ee | 66 | static void elsa_cs_release(struct pcmcia_device *link); |
f61bb62e | 67 | static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit; |
1da177e4 | 68 | |
1da177e4 | 69 | typedef struct local_info_t { |
fd238232 | 70 | struct pcmcia_device *p_dev; |
475be4d8 JP |
71 | int busy; |
72 | int cardnr; | |
1da177e4 LT |
73 | } local_info_t; |
74 | ||
f61bb62e | 75 | static int __devinit elsa_cs_probe(struct pcmcia_device *link) |
1da177e4 | 76 | { |
475be4d8 | 77 | local_info_t *local; |
1da177e4 | 78 | |
475be4d8 | 79 | dev_dbg(&link->dev, "elsa_cs_attach()\n"); |
1da177e4 | 80 | |
475be4d8 JP |
81 | /* Allocate space for private device-specific data */ |
82 | local = kzalloc(sizeof(local_info_t), GFP_KERNEL); | |
83 | if (!local) return -ENOMEM; | |
fd238232 | 84 | |
475be4d8 JP |
85 | local->p_dev = link; |
86 | link->priv = local; | |
fd238232 | 87 | |
475be4d8 | 88 | local->cardnr = -1; |
1da177e4 | 89 | |
475be4d8 | 90 | return elsa_cs_config(link); |
1da177e4 LT |
91 | } /* elsa_cs_attach */ |
92 | ||
f61bb62e | 93 | static void __devexit elsa_cs_detach(struct pcmcia_device *link) |
1da177e4 | 94 | { |
e2d40963 | 95 | local_info_t *info = link->priv; |
1da177e4 | 96 | |
e773cfe1 | 97 | dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link); |
1da177e4 | 98 | |
e2d40963 DB |
99 | info->busy = 1; |
100 | elsa_cs_release(link); | |
1da177e4 | 101 | |
e2d40963 | 102 | kfree(info); |
1da177e4 LT |
103 | } /* elsa_cs_detach */ |
104 | ||
00990e7c | 105 | static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) |
1da177e4 | 106 | { |
5fcd4da0 DB |
107 | int j; |
108 | ||
90abdc3b | 109 | p_dev->io_lines = 3; |
00990e7c DB |
110 | 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; | |
90abdc3b | 113 | |
00990e7c | 114 | if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { |
5fcd4da0 | 115 | printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); |
90abdc3b | 116 | if (!pcmcia_request_io(p_dev)) |
5fcd4da0 DB |
117 | return 0; |
118 | } else { | |
119 | printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); | |
5fcd4da0 | 120 | for (j = 0x2f0; j > 0x100; j -= 0x10) { |
90abdc3b DB |
121 | p_dev->resource[0]->start = j; |
122 | if (!pcmcia_request_io(p_dev)) | |
5fcd4da0 DB |
123 | return 0; |
124 | } | |
125 | } | |
126 | return -ENODEV; | |
1da177e4 LT |
127 | } |
128 | ||
f61bb62e | 129 | static int __devinit elsa_cs_config(struct pcmcia_device *link) |
1da177e4 | 130 | { |
475be4d8 JP |
131 | int i; |
132 | IsdnCard_t icard; | |
133 | ||
134 | dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); | |
135 | ||
136 | link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; | |
137 | ||
138 | i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL); | |
139 | if (i != 0) | |
140 | goto failed; | |
141 | ||
142 | if (!link->irq) | |
143 | goto failed; | |
144 | ||
145 | i = pcmcia_enable_device(link); | |
146 | if (i != 0) | |
147 | goto failed; | |
148 | ||
149 | icard.para[0] = link->irq; | |
150 | icard.para[1] = link->resource[0]->start; | |
151 | icard.protocol = protocol; | |
152 | icard.typ = ISDN_CTYPE_ELSA_PCMCIA; | |
153 | ||
154 | 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; | |
e773cfe1 | 163 | failed: |
475be4d8 JP |
164 | elsa_cs_release(link); |
165 | return -ENODEV; | |
1da177e4 LT |
166 | } /* elsa_cs_config */ |
167 | ||
fba395ee | 168 | static void elsa_cs_release(struct pcmcia_device *link) |
1da177e4 | 169 | { |
475be4d8 | 170 | local_info_t *local = link->priv; |
1da177e4 | 171 | |
475be4d8 | 172 | dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link); |
1da177e4 | 173 | |
475be4d8 JP |
174 | if (local) { |
175 | if (local->cardnr >= 0) { | |
176 | /* no unregister function with hisax */ | |
177 | HiSax_closecard(local->cardnr); | |
178 | } | |
1da177e4 | 179 | } |
5f2a71fc | 180 | |
475be4d8 | 181 | pcmcia_disable_device(link); |
1da177e4 LT |
182 | } /* elsa_cs_release */ |
183 | ||
fba395ee | 184 | static int elsa_suspend(struct pcmcia_device *link) |
98e4c28b | 185 | { |
98e4c28b DB |
186 | local_info_t *dev = link->priv; |
187 | ||
475be4d8 | 188 | dev->busy = 1; |
98e4c28b DB |
189 | |
190 | return 0; | |
191 | } | |
192 | ||
fba395ee | 193 | static int elsa_resume(struct pcmcia_device *link) |
98e4c28b | 194 | { |
98e4c28b DB |
195 | local_info_t *dev = link->priv; |
196 | ||
475be4d8 | 197 | dev->busy = 0; |
98e4c28b DB |
198 | |
199 | return 0; | |
200 | } | |
201 | ||
25f8f54f | 202 | static const struct pcmcia_device_id elsa_ids[] = { |
02ae38cf DB |
203 | 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 | }; | |
207 | MODULE_DEVICE_TABLE(pcmcia, elsa_ids); | |
208 | ||
1da177e4 LT |
209 | static struct pcmcia_driver elsa_cs_driver = { |
210 | .owner = THIS_MODULE, | |
2e9b981a | 211 | .name = "elsa_cs", |
15b99ac1 | 212 | .probe = elsa_cs_probe, |
f61bb62e | 213 | .remove = __devexit_p(elsa_cs_detach), |
02ae38cf | 214 | .id_table = elsa_ids, |
98e4c28b DB |
215 | .suspend = elsa_suspend, |
216 | .resume = elsa_resume, | |
1da177e4 LT |
217 | }; |
218 | ||
219 | static int __init init_elsa_cs(void) | |
220 | { | |
221 | return pcmcia_register_driver(&elsa_cs_driver); | |
222 | } | |
223 | ||
224 | static void __exit exit_elsa_cs(void) | |
225 | { | |
226 | pcmcia_unregister_driver(&elsa_cs_driver); | |
1da177e4 LT |
227 | } |
228 | ||
229 | module_init(init_elsa_cs); | |
230 | module_exit(exit_elsa_cs); |