diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hardware/avm |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hardware/avm')
-rw-r--r-- | drivers/isdn/hardware/avm/Kconfig | 66 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/Makefile | 11 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/avm_cs.c | 510 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/avmcard.h | 585 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/b1.c | 814 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/b1dma.c | 980 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/b1isa.c | 245 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/b1pci.c | 417 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/b1pcmcia.c | 224 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/c4.c | 1310 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/t1isa.c | 596 | ||||
-rw-r--r-- | drivers/isdn/hardware/avm/t1pci.c | 260 |
12 files changed, 6018 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig new file mode 100644 index 000000000000..29a32a8830c0 --- /dev/null +++ b/drivers/isdn/hardware/avm/Kconfig | |||
@@ -0,0 +1,66 @@ | |||
1 | # | ||
2 | # ISDN AVM drivers | ||
3 | # | ||
4 | |||
5 | menu "Active AVM cards" | ||
6 | depends on NET && ISDN && ISDN_CAPI!=n | ||
7 | |||
8 | config CAPI_AVM | ||
9 | bool "Support AVM cards" | ||
10 | help | ||
11 | Enable support for AVM active ISDN cards. | ||
12 | |||
13 | config ISDN_DRV_AVMB1_B1ISA | ||
14 | tristate "AVM B1 ISA support" | ||
15 | depends on CAPI_AVM && ISDN_CAPI && ISA | ||
16 | help | ||
17 | Enable support for the ISA version of the AVM B1 card. | ||
18 | |||
19 | config ISDN_DRV_AVMB1_B1PCI | ||
20 | tristate "AVM B1 PCI support" | ||
21 | depends on CAPI_AVM && ISDN_CAPI && PCI | ||
22 | help | ||
23 | Enable support for the PCI version of the AVM B1 card. | ||
24 | |||
25 | config ISDN_DRV_AVMB1_B1PCIV4 | ||
26 | bool "AVM B1 PCI V4 support" | ||
27 | depends on ISDN_DRV_AVMB1_B1PCI | ||
28 | help | ||
29 | Enable support for the V4 version of AVM B1 PCI card. | ||
30 | |||
31 | config ISDN_DRV_AVMB1_T1ISA | ||
32 | tristate "AVM T1/T1-B ISA support" | ||
33 | depends on CAPI_AVM && ISDN_CAPI && ISA | ||
34 | help | ||
35 | Enable support for the AVM T1 T1B card. | ||
36 | Note: This is a PRI card and handle 30 B-channels. | ||
37 | |||
38 | config ISDN_DRV_AVMB1_B1PCMCIA | ||
39 | tristate "AVM B1/M1/M2 PCMCIA support" | ||
40 | depends on CAPI_AVM && ISDN_CAPI | ||
41 | help | ||
42 | Enable support for the PCMCIA version of the AVM B1 card. | ||
43 | |||
44 | config ISDN_DRV_AVMB1_AVM_CS | ||
45 | tristate "AVM B1/M1/M2 PCMCIA cs module" | ||
46 | depends on ISDN_DRV_AVMB1_B1PCMCIA && PCMCIA | ||
47 | help | ||
48 | Enable the PCMCIA client driver for the AVM B1/M1/M2 | ||
49 | PCMCIA cards. | ||
50 | |||
51 | config ISDN_DRV_AVMB1_T1PCI | ||
52 | tristate "AVM T1/T1-B PCI support" | ||
53 | depends on CAPI_AVM && ISDN_CAPI && PCI | ||
54 | help | ||
55 | Enable support for the AVM T1 T1B card. | ||
56 | Note: This is a PRI card and handle 30 B-channels. | ||
57 | |||
58 | config ISDN_DRV_AVMB1_C4 | ||
59 | tristate "AVM C4/C2 support" | ||
60 | depends on CAPI_AVM && ISDN_CAPI && PCI | ||
61 | help | ||
62 | Enable support for the AVM C4/C2 PCI cards. | ||
63 | These cards handle 4/2 BRI ISDN lines (8/4 channels). | ||
64 | |||
65 | endmenu | ||
66 | |||
diff --git a/drivers/isdn/hardware/avm/Makefile b/drivers/isdn/hardware/avm/Makefile new file mode 100644 index 000000000000..b540e8f2efb6 --- /dev/null +++ b/drivers/isdn/hardware/avm/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # Makefile for the AVM ISDN device drivers | ||
2 | |||
3 | # Each configuration option enables a list of files. | ||
4 | |||
5 | obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA) += b1isa.o b1.o | ||
6 | obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI) += b1pci.o b1.o b1dma.o | ||
7 | obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA) += b1pcmcia.o b1.o | ||
8 | obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS) += avm_cs.o | ||
9 | obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA) += t1isa.o b1.o | ||
10 | obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI) += t1pci.o b1.o b1dma.o | ||
11 | obj-$(CONFIG_ISDN_DRV_AVMB1_C4) += c4.o b1.o | ||
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c new file mode 100644 index 000000000000..dc00c85e3e35 --- /dev/null +++ b/drivers/isdn/hardware/avm/avm_cs.c | |||
@@ -0,0 +1,510 @@ | |||
1 | /* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $ | ||
2 | * | ||
3 | * A PCMCIA client driver for AVM B1/M1/M2 | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/ptrace.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/tty.h> | ||
20 | #include <linux/serial.h> | ||
21 | #include <linux/major.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/system.h> | ||
24 | |||
25 | #include <pcmcia/version.h> | ||
26 | #include <pcmcia/cs_types.h> | ||
27 | #include <pcmcia/cs.h> | ||
28 | #include <pcmcia/cistpl.h> | ||
29 | #include <pcmcia/ciscode.h> | ||
30 | #include <pcmcia/ds.h> | ||
31 | #include <pcmcia/cisreg.h> | ||
32 | |||
33 | #include <linux/skbuff.h> | ||
34 | #include <linux/capi.h> | ||
35 | #include <linux/b1lli.h> | ||
36 | #include <linux/b1pcmcia.h> | ||
37 | |||
38 | /*====================================================================*/ | ||
39 | |||
40 | MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2"); | ||
41 | MODULE_AUTHOR("Carsten Paeth"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | /*====================================================================*/ | ||
45 | |||
46 | /* | ||
47 | The event() function is this driver's Card Services event handler. | ||
48 | It will be called by Card Services when an appropriate card status | ||
49 | event is received. The config() and release() entry points are | ||
50 | used to configure or release a socket, in response to card insertion | ||
51 | and ejection events. They are invoked from the skeleton event | ||
52 | handler. | ||
53 | */ | ||
54 | |||
55 | static void avmcs_config(dev_link_t *link); | ||
56 | static void avmcs_release(dev_link_t *link); | ||
57 | static int avmcs_event(event_t event, int priority, | ||
58 | event_callback_args_t *args); | ||
59 | |||
60 | /* | ||
61 | The attach() and detach() entry points are used to create and destroy | ||
62 | "instances" of the driver, where each instance represents everything | ||
63 | needed to manage one actual PCMCIA card. | ||
64 | */ | ||
65 | |||
66 | static dev_link_t *avmcs_attach(void); | ||
67 | static void avmcs_detach(dev_link_t *); | ||
68 | |||
69 | /* | ||
70 | The dev_info variable is the "key" that is used to match up this | ||
71 | device driver with appropriate cards, through the card configuration | ||
72 | database. | ||
73 | */ | ||
74 | |||
75 | static dev_info_t dev_info = "avm_cs"; | ||
76 | |||
77 | /* | ||
78 | A linked list of "instances" of the skeleton device. Each actual | ||
79 | PCMCIA card corresponds to one device instance, and is described | ||
80 | by one dev_link_t structure (defined in ds.h). | ||
81 | |||
82 | You may not want to use a linked list for this -- for example, the | ||
83 | memory card driver uses an array of dev_link_t pointers, where minor | ||
84 | device numbers are used to derive the corresponding array index. | ||
85 | */ | ||
86 | |||
87 | static dev_link_t *dev_list = NULL; | ||
88 | |||
89 | /* | ||
90 | A dev_link_t structure has fields for most things that are needed | ||
91 | to keep track of a socket, but there will usually be some device | ||
92 | specific information that also needs to be kept track of. The | ||
93 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
94 | a device-specific private data structure, like this. | ||
95 | |||
96 | A driver needs to provide a dev_node_t structure for each device | ||
97 | on a card. In some cases, there is only one device per card (for | ||
98 | example, ethernet cards, modems). In other cases, there may be | ||
99 | many actual or logical devices (SCSI adapters, memory cards with | ||
100 | multiple partitions). The dev_node_t structures need to be kept | ||
101 | in a linked list starting at the 'dev' field of a dev_link_t | ||
102 | structure. We allocate them in the card's private data structure, | ||
103 | because they generally can't be allocated dynamically. | ||
104 | */ | ||
105 | |||
106 | typedef struct local_info_t { | ||
107 | dev_node_t node; | ||
108 | } local_info_t; | ||
109 | |||
110 | /*====================================================================== | ||
111 | |||
112 | avmcs_attach() creates an "instance" of the driver, allocating | ||
113 | local data structures for one device. The device is registered | ||
114 | with Card Services. | ||
115 | |||
116 | The dev_link structure is initialized, but we don't actually | ||
117 | configure the card at this point -- we wait until we receive a | ||
118 | card insertion event. | ||
119 | |||
120 | ======================================================================*/ | ||
121 | |||
122 | static dev_link_t *avmcs_attach(void) | ||
123 | { | ||
124 | client_reg_t client_reg; | ||
125 | dev_link_t *link; | ||
126 | local_info_t *local; | ||
127 | int ret; | ||
128 | |||
129 | /* Initialize the dev_link_t structure */ | ||
130 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | ||
131 | if (!link) | ||
132 | goto err; | ||
133 | memset(link, 0, sizeof(struct dev_link_t)); | ||
134 | |||
135 | /* The io structure describes IO port mapping */ | ||
136 | link->io.NumPorts1 = 16; | ||
137 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
138 | link->io.NumPorts2 = 0; | ||
139 | |||
140 | /* Interrupt setup */ | ||
141 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; | ||
142 | link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; | ||
143 | |||
144 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
145 | |||
146 | /* General socket configuration */ | ||
147 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
148 | link->conf.Vcc = 50; | ||
149 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
150 | link->conf.ConfigIndex = 1; | ||
151 | link->conf.Present = PRESENT_OPTION; | ||
152 | |||
153 | /* Allocate space for private device-specific data */ | ||
154 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | ||
155 | if (!local) | ||
156 | goto err_kfree; | ||
157 | memset(local, 0, sizeof(local_info_t)); | ||
158 | link->priv = local; | ||
159 | |||
160 | /* Register with Card Services */ | ||
161 | link->next = dev_list; | ||
162 | dev_list = link; | ||
163 | client_reg.dev_info = &dev_info; | ||
164 | client_reg.EventMask = | ||
165 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
166 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
167 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
168 | client_reg.event_handler = &avmcs_event; | ||
169 | client_reg.Version = 0x0210; | ||
170 | client_reg.event_callback_args.client_data = link; | ||
171 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
172 | if (ret != 0) { | ||
173 | cs_error(link->handle, RegisterClient, ret); | ||
174 | avmcs_detach(link); | ||
175 | goto err; | ||
176 | } | ||
177 | return link; | ||
178 | |||
179 | err_kfree: | ||
180 | kfree(link); | ||
181 | err: | ||
182 | return NULL; | ||
183 | } /* avmcs_attach */ | ||
184 | |||
185 | /*====================================================================== | ||
186 | |||
187 | This deletes a driver "instance". The device is de-registered | ||
188 | with Card Services. If it has been released, all local data | ||
189 | structures are freed. Otherwise, the structures will be freed | ||
190 | when the device is released. | ||
191 | |||
192 | ======================================================================*/ | ||
193 | |||
194 | static void avmcs_detach(dev_link_t *link) | ||
195 | { | ||
196 | dev_link_t **linkp; | ||
197 | |||
198 | /* Locate device structure */ | ||
199 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
200 | if (*linkp == link) break; | ||
201 | if (*linkp == NULL) | ||
202 | return; | ||
203 | |||
204 | /* | ||
205 | If the device is currently configured and active, we won't | ||
206 | actually delete it yet. Instead, it is marked so that when | ||
207 | the release() function is called, that will trigger a proper | ||
208 | detach(). | ||
209 | */ | ||
210 | if (link->state & DEV_CONFIG) { | ||
211 | link->state |= DEV_STALE_LINK; | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | /* Break the link with Card Services */ | ||
216 | if (link->handle) | ||
217 | pcmcia_deregister_client(link->handle); | ||
218 | |||
219 | /* Unlink device structure, free pieces */ | ||
220 | *linkp = link->next; | ||
221 | if (link->priv) { | ||
222 | kfree(link->priv); | ||
223 | } | ||
224 | kfree(link); | ||
225 | |||
226 | } /* avmcs_detach */ | ||
227 | |||
228 | /*====================================================================== | ||
229 | |||
230 | avmcs_config() is scheduled to run after a CARD_INSERTION event | ||
231 | is received, to configure the PCMCIA socket, and to make the | ||
232 | ethernet device available to the system. | ||
233 | |||
234 | ======================================================================*/ | ||
235 | |||
236 | static int get_tuple(client_handle_t handle, tuple_t *tuple, | ||
237 | cisparse_t *parse) | ||
238 | { | ||
239 | int i = pcmcia_get_tuple_data(handle, tuple); | ||
240 | if (i != CS_SUCCESS) return i; | ||
241 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
242 | } | ||
243 | |||
244 | static int first_tuple(client_handle_t handle, tuple_t *tuple, | ||
245 | cisparse_t *parse) | ||
246 | { | ||
247 | int i = pcmcia_get_first_tuple(handle, tuple); | ||
248 | if (i != CS_SUCCESS) return i; | ||
249 | return get_tuple(handle, tuple, parse); | ||
250 | } | ||
251 | |||
252 | static int next_tuple(client_handle_t handle, tuple_t *tuple, | ||
253 | cisparse_t *parse) | ||
254 | { | ||
255 | int i = pcmcia_get_next_tuple(handle, tuple); | ||
256 | if (i != CS_SUCCESS) return i; | ||
257 | return get_tuple(handle, tuple, parse); | ||
258 | } | ||
259 | |||
260 | static void avmcs_config(dev_link_t *link) | ||
261 | { | ||
262 | client_handle_t handle; | ||
263 | tuple_t tuple; | ||
264 | cisparse_t parse; | ||
265 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | ||
266 | local_info_t *dev; | ||
267 | int i; | ||
268 | u_char buf[64]; | ||
269 | char devname[128]; | ||
270 | int cardtype; | ||
271 | int (*addcard)(unsigned int port, unsigned irq); | ||
272 | |||
273 | handle = link->handle; | ||
274 | dev = link->priv; | ||
275 | |||
276 | /* | ||
277 | This reads the card's CONFIG tuple to find its configuration | ||
278 | registers. | ||
279 | */ | ||
280 | do { | ||
281 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
282 | i = pcmcia_get_first_tuple(handle, &tuple); | ||
283 | if (i != CS_SUCCESS) break; | ||
284 | tuple.TupleData = buf; | ||
285 | tuple.TupleDataMax = 64; | ||
286 | tuple.TupleOffset = 0; | ||
287 | i = pcmcia_get_tuple_data(handle, &tuple); | ||
288 | if (i != CS_SUCCESS) break; | ||
289 | i = pcmcia_parse_tuple(handle, &tuple, &parse); | ||
290 | if (i != CS_SUCCESS) break; | ||
291 | link->conf.ConfigBase = parse.config.base; | ||
292 | } while (0); | ||
293 | if (i != CS_SUCCESS) { | ||
294 | cs_error(link->handle, ParseTuple, i); | ||
295 | link->state &= ~DEV_CONFIG_PENDING; | ||
296 | return; | ||
297 | } | ||
298 | |||
299 | /* Configure card */ | ||
300 | link->state |= DEV_CONFIG; | ||
301 | |||
302 | do { | ||
303 | |||
304 | tuple.Attributes = 0; | ||
305 | tuple.TupleData = buf; | ||
306 | tuple.TupleDataMax = 254; | ||
307 | tuple.TupleOffset = 0; | ||
308 | tuple.DesiredTuple = CISTPL_VERS_1; | ||
309 | |||
310 | devname[0] = 0; | ||
311 | if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { | ||
312 | strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], | ||
313 | sizeof(devname)); | ||
314 | } | ||
315 | /* | ||
316 | * find IO port | ||
317 | */ | ||
318 | tuple.TupleData = (cisdata_t *)buf; | ||
319 | tuple.TupleOffset = 0; tuple.TupleDataMax = 255; | ||
320 | tuple.Attributes = 0; | ||
321 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
322 | i = first_tuple(handle, &tuple, &parse); | ||
323 | while (i == CS_SUCCESS) { | ||
324 | if (cf->io.nwin > 0) { | ||
325 | link->conf.ConfigIndex = cf->index; | ||
326 | link->io.BasePort1 = cf->io.win[0].base; | ||
327 | link->io.NumPorts1 = cf->io.win[0].len; | ||
328 | link->io.NumPorts2 = 0; | ||
329 | printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", | ||
330 | link->io.BasePort1, | ||
331 | link->io.BasePort1+link->io.NumPorts1-1); | ||
332 | i = pcmcia_request_io(link->handle, &link->io); | ||
333 | if (i == CS_SUCCESS) goto found_port; | ||
334 | } | ||
335 | i = next_tuple(handle, &tuple, &parse); | ||
336 | } | ||
337 | |||
338 | found_port: | ||
339 | if (i != CS_SUCCESS) { | ||
340 | cs_error(link->handle, RequestIO, i); | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * allocate an interrupt line | ||
346 | */ | ||
347 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
348 | if (i != CS_SUCCESS) { | ||
349 | cs_error(link->handle, RequestIRQ, i); | ||
350 | pcmcia_release_io(link->handle, &link->io); | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * configure the PCMCIA socket | ||
356 | */ | ||
357 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
358 | if (i != CS_SUCCESS) { | ||
359 | cs_error(link->handle, RequestConfiguration, i); | ||
360 | pcmcia_release_io(link->handle, &link->io); | ||
361 | pcmcia_release_irq(link->handle, &link->irq); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | } while (0); | ||
366 | |||
367 | /* At this point, the dev_node_t structure(s) should be | ||
368 | initialized and arranged in a linked list at link->dev. */ | ||
369 | |||
370 | if (devname[0]) { | ||
371 | char *s = strrchr(devname, ' '); | ||
372 | if (!s) | ||
373 | s = devname; | ||
374 | else s++; | ||
375 | strcpy(dev->node.dev_name, s); | ||
376 | if (strcmp("M1", s) == 0) { | ||
377 | cardtype = AVM_CARDTYPE_M1; | ||
378 | } else if (strcmp("M2", s) == 0) { | ||
379 | cardtype = AVM_CARDTYPE_M2; | ||
380 | } else { | ||
381 | cardtype = AVM_CARDTYPE_B1; | ||
382 | } | ||
383 | } else { | ||
384 | strcpy(dev->node.dev_name, "b1"); | ||
385 | cardtype = AVM_CARDTYPE_B1; | ||
386 | } | ||
387 | |||
388 | dev->node.major = 64; | ||
389 | dev->node.minor = 0; | ||
390 | link->dev = &dev->node; | ||
391 | |||
392 | link->state &= ~DEV_CONFIG_PENDING; | ||
393 | /* If any step failed, release any partially configured state */ | ||
394 | if (i != 0) { | ||
395 | avmcs_release(link); | ||
396 | return; | ||
397 | } | ||
398 | |||
399 | |||
400 | switch (cardtype) { | ||
401 | case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; | ||
402 | case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; | ||
403 | default: | ||
404 | case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; | ||
405 | } | ||
406 | if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) { | ||
407 | printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", | ||
408 | dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); | ||
409 | avmcs_release(link); | ||
410 | return; | ||
411 | } | ||
412 | dev->node.minor = i; | ||
413 | |||
414 | } /* avmcs_config */ | ||
415 | |||
416 | /*====================================================================== | ||
417 | |||
418 | After a card is removed, avmcs_release() will unregister the net | ||
419 | device, and release the PCMCIA configuration. If the device is | ||
420 | still open, this will be postponed until it is closed. | ||
421 | |||
422 | ======================================================================*/ | ||
423 | |||
424 | static void avmcs_release(dev_link_t *link) | ||
425 | { | ||
426 | b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); | ||
427 | |||
428 | /* Unlink the device chain */ | ||
429 | link->dev = NULL; | ||
430 | |||
431 | /* Don't bother checking to see if these succeed or not */ | ||
432 | pcmcia_release_configuration(link->handle); | ||
433 | pcmcia_release_io(link->handle, &link->io); | ||
434 | pcmcia_release_irq(link->handle, &link->irq); | ||
435 | link->state &= ~DEV_CONFIG; | ||
436 | |||
437 | if (link->state & DEV_STALE_LINK) | ||
438 | avmcs_detach(link); | ||
439 | |||
440 | } /* avmcs_release */ | ||
441 | |||
442 | /*====================================================================== | ||
443 | |||
444 | The card status event handler. Mostly, this schedules other | ||
445 | stuff to run after an event is received. A CARD_REMOVAL event | ||
446 | also sets some flags to discourage the net drivers from trying | ||
447 | to talk to the card any more. | ||
448 | |||
449 | When a CARD_REMOVAL event is received, we immediately set a flag | ||
450 | to block future accesses to this device. All the functions that | ||
451 | actually access the device should check this flag to make sure | ||
452 | the card is still present. | ||
453 | |||
454 | ======================================================================*/ | ||
455 | |||
456 | static int avmcs_event(event_t event, int priority, | ||
457 | event_callback_args_t *args) | ||
458 | { | ||
459 | dev_link_t *link = args->client_data; | ||
460 | |||
461 | switch (event) { | ||
462 | case CS_EVENT_CARD_REMOVAL: | ||
463 | link->state &= ~DEV_PRESENT; | ||
464 | if (link->state & DEV_CONFIG) | ||
465 | avmcs_release(link); | ||
466 | break; | ||
467 | case CS_EVENT_CARD_INSERTION: | ||
468 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
469 | avmcs_config(link); | ||
470 | break; | ||
471 | case CS_EVENT_PM_SUSPEND: | ||
472 | link->state |= DEV_SUSPEND; | ||
473 | /* Fall through... */ | ||
474 | case CS_EVENT_RESET_PHYSICAL: | ||
475 | if (link->state & DEV_CONFIG) | ||
476 | pcmcia_release_configuration(link->handle); | ||
477 | break; | ||
478 | case CS_EVENT_PM_RESUME: | ||
479 | link->state &= ~DEV_SUSPEND; | ||
480 | /* Fall through... */ | ||
481 | case CS_EVENT_CARD_RESET: | ||
482 | if (link->state & DEV_CONFIG) | ||
483 | pcmcia_request_configuration(link->handle, &link->conf); | ||
484 | break; | ||
485 | } | ||
486 | return 0; | ||
487 | } /* avmcs_event */ | ||
488 | |||
489 | static struct pcmcia_driver avmcs_driver = { | ||
490 | .owner = THIS_MODULE, | ||
491 | .drv = { | ||
492 | .name = "avm_cs", | ||
493 | }, | ||
494 | .attach = avmcs_attach, | ||
495 | .detach = avmcs_detach, | ||
496 | }; | ||
497 | |||
498 | static int __init avmcs_init(void) | ||
499 | { | ||
500 | return pcmcia_register_driver(&avmcs_driver); | ||
501 | } | ||
502 | |||
503 | static void __exit avmcs_exit(void) | ||
504 | { | ||
505 | pcmcia_unregister_driver(&avmcs_driver); | ||
506 | BUG_ON(dev_list != NULL); | ||
507 | } | ||
508 | |||
509 | module_init(avmcs_init); | ||
510 | module_exit(avmcs_exit); | ||
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h new file mode 100644 index 000000000000..296d6a6f749f --- /dev/null +++ b/drivers/isdn/hardware/avm/avmcard.h | |||
@@ -0,0 +1,585 @@ | |||
1 | /* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ | ||
2 | * | ||
3 | * Copyright 1999 by Carsten Paeth <calle@calle.de> | ||
4 | * | ||
5 | * This software may be used and distributed according to the terms | ||
6 | * of the GNU General Public License, incorporated herein by reference. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef _AVMCARD_H_ | ||
11 | #define _AVMCARD_H_ | ||
12 | |||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | |||
17 | #define AVMB1_PORTLEN 0x1f | ||
18 | #define AVM_MAXVERSION 8 | ||
19 | #define AVM_NCCI_PER_CHANNEL 4 | ||
20 | |||
21 | /* | ||
22 | * Versions | ||
23 | */ | ||
24 | |||
25 | #define VER_DRIVER 0 | ||
26 | #define VER_CARDTYPE 1 | ||
27 | #define VER_HWID 2 | ||
28 | #define VER_SERIAL 3 | ||
29 | #define VER_OPTION 4 | ||
30 | #define VER_PROTO 5 | ||
31 | #define VER_PROFILE 6 | ||
32 | #define VER_CAPI 7 | ||
33 | |||
34 | enum avmcardtype { | ||
35 | avm_b1isa, | ||
36 | avm_b1pci, | ||
37 | avm_b1pcmcia, | ||
38 | avm_m1, | ||
39 | avm_m2, | ||
40 | avm_t1isa, | ||
41 | avm_t1pci, | ||
42 | avm_c4, | ||
43 | avm_c2 | ||
44 | }; | ||
45 | |||
46 | typedef struct avmcard_dmabuf { | ||
47 | long size; | ||
48 | u8 *dmabuf; | ||
49 | dma_addr_t dmaaddr; | ||
50 | } avmcard_dmabuf; | ||
51 | |||
52 | typedef struct avmcard_dmainfo { | ||
53 | u32 recvlen; | ||
54 | avmcard_dmabuf recvbuf; | ||
55 | |||
56 | avmcard_dmabuf sendbuf; | ||
57 | struct sk_buff_head send_queue; | ||
58 | |||
59 | struct pci_dev *pcidev; | ||
60 | } avmcard_dmainfo; | ||
61 | |||
62 | typedef struct avmctrl_info { | ||
63 | char cardname[32]; | ||
64 | |||
65 | int versionlen; | ||
66 | char versionbuf[1024]; | ||
67 | char *version[AVM_MAXVERSION]; | ||
68 | |||
69 | char infobuf[128]; /* for function procinfo */ | ||
70 | |||
71 | struct avmcard *card; | ||
72 | struct capi_ctr capi_ctrl; | ||
73 | |||
74 | struct list_head ncci_head; | ||
75 | } avmctrl_info; | ||
76 | |||
77 | typedef struct avmcard { | ||
78 | char name[32]; | ||
79 | |||
80 | spinlock_t lock; | ||
81 | unsigned int port; | ||
82 | unsigned irq; | ||
83 | unsigned long membase; | ||
84 | enum avmcardtype cardtype; | ||
85 | unsigned char revision; | ||
86 | unsigned char class; | ||
87 | int cardnr; /* for t1isa */ | ||
88 | |||
89 | char msgbuf[128]; /* capimsg msg part */ | ||
90 | char databuf[2048]; /* capimsg data part */ | ||
91 | |||
92 | void __iomem *mbase; | ||
93 | volatile u32 csr; | ||
94 | avmcard_dmainfo *dma; | ||
95 | |||
96 | struct avmctrl_info *ctrlinfo; | ||
97 | |||
98 | u_int nr_controllers; | ||
99 | u_int nlogcontr; | ||
100 | struct list_head list; | ||
101 | } avmcard; | ||
102 | |||
103 | extern int b1_irq_table[16]; | ||
104 | |||
105 | /* | ||
106 | * LLI Messages to the ISDN-ControllerISDN Controller | ||
107 | */ | ||
108 | |||
109 | #define SEND_POLL 0x72 /* | ||
110 | * after load <- RECEIVE_POLL | ||
111 | */ | ||
112 | #define SEND_INIT 0x11 /* | ||
113 | * first message <- RECEIVE_INIT | ||
114 | * int32 NumApplications int32 | ||
115 | * NumNCCIs int32 BoardNumber | ||
116 | */ | ||
117 | #define SEND_REGISTER 0x12 /* | ||
118 | * register an application int32 | ||
119 | * ApplIDId int32 NumMessages | ||
120 | * int32 NumB3Connections int32 | ||
121 | * NumB3Blocks int32 B3Size | ||
122 | * | ||
123 | * AnzB3Connection != 0 && | ||
124 | * AnzB3Blocks >= 1 && B3Size >= 1 | ||
125 | */ | ||
126 | #define SEND_RELEASE 0x14 /* | ||
127 | * deregister an application int32 | ||
128 | * ApplID | ||
129 | */ | ||
130 | #define SEND_MESSAGE 0x15 /* | ||
131 | * send capi-message int32 length | ||
132 | * capi-data ... | ||
133 | */ | ||
134 | #define SEND_DATA_B3_REQ 0x13 /* | ||
135 | * send capi-data-message int32 | ||
136 | * MsgLength capi-data ... int32 | ||
137 | * B3Length data .... | ||
138 | */ | ||
139 | |||
140 | #define SEND_CONFIG 0x21 /* | ||
141 | */ | ||
142 | |||
143 | #define SEND_POLLACK 0x73 /* T1 Watchdog */ | ||
144 | |||
145 | /* | ||
146 | * LLI Messages from the ISDN-ControllerISDN Controller | ||
147 | */ | ||
148 | |||
149 | #define RECEIVE_POLL 0x32 /* | ||
150 | * <- after SEND_POLL | ||
151 | */ | ||
152 | #define RECEIVE_INIT 0x27 /* | ||
153 | * <- after SEND_INIT int32 length | ||
154 | * byte total length b1struct board | ||
155 | * driver revision b1struct card | ||
156 | * type b1struct reserved b1struct | ||
157 | * serial number b1struct driver | ||
158 | * capability b1struct d-channel | ||
159 | * protocol b1struct CAPI-2.0 | ||
160 | * profile b1struct capi version | ||
161 | */ | ||
162 | #define RECEIVE_MESSAGE 0x21 /* | ||
163 | * <- after SEND_MESSAGE int32 | ||
164 | * AppllID int32 Length capi-data | ||
165 | * .... | ||
166 | */ | ||
167 | #define RECEIVE_DATA_B3_IND 0x22 /* | ||
168 | * received data int32 AppllID | ||
169 | * int32 Length capi-data ... | ||
170 | * int32 B3Length data ... | ||
171 | */ | ||
172 | #define RECEIVE_START 0x23 /* | ||
173 | * Handshake | ||
174 | */ | ||
175 | #define RECEIVE_STOP 0x24 /* | ||
176 | * Handshake | ||
177 | */ | ||
178 | #define RECEIVE_NEW_NCCI 0x25 /* | ||
179 | * int32 AppllID int32 NCCI int32 | ||
180 | * WindowSize | ||
181 | */ | ||
182 | #define RECEIVE_FREE_NCCI 0x26 /* | ||
183 | * int32 AppllID int32 NCCI | ||
184 | */ | ||
185 | #define RECEIVE_RELEASE 0x26 /* | ||
186 | * int32 AppllID int32 0xffffffff | ||
187 | */ | ||
188 | #define RECEIVE_TASK_READY 0x31 /* | ||
189 | * int32 tasknr | ||
190 | * int32 Length Taskname ... | ||
191 | */ | ||
192 | #define RECEIVE_DEBUGMSG 0x71 /* | ||
193 | * int32 Length message | ||
194 | * | ||
195 | */ | ||
196 | #define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */ | ||
197 | |||
198 | #define WRITE_REGISTER 0x00 | ||
199 | #define READ_REGISTER 0x01 | ||
200 | |||
201 | /* | ||
202 | * port offsets | ||
203 | */ | ||
204 | |||
205 | #define B1_READ 0x00 | ||
206 | #define B1_WRITE 0x01 | ||
207 | #define B1_INSTAT 0x02 | ||
208 | #define B1_OUTSTAT 0x03 | ||
209 | #define B1_ANALYSE 0x04 | ||
210 | #define B1_REVISION 0x05 | ||
211 | #define B1_RESET 0x10 | ||
212 | |||
213 | |||
214 | #define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l) | ||
215 | #define B1_STAT1(cardtype) (0x80E00000l) | ||
216 | |||
217 | /* ---------------------------------------------------------------- */ | ||
218 | |||
219 | static inline unsigned char b1outp(unsigned int base, | ||
220 | unsigned short offset, | ||
221 | unsigned char value) | ||
222 | { | ||
223 | outb(value, base + offset); | ||
224 | return inb(base + B1_ANALYSE); | ||
225 | } | ||
226 | |||
227 | |||
228 | static inline int b1_rx_full(unsigned int base) | ||
229 | { | ||
230 | return inb(base + B1_INSTAT) & 0x1; | ||
231 | } | ||
232 | |||
233 | static inline unsigned char b1_get_byte(unsigned int base) | ||
234 | { | ||
235 | unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ | ||
236 | while (!b1_rx_full(base) && time_before(jiffies, stop)); | ||
237 | if (b1_rx_full(base)) | ||
238 | return inb(base + B1_READ); | ||
239 | printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static inline unsigned int b1_get_word(unsigned int base) | ||
244 | { | ||
245 | unsigned int val = 0; | ||
246 | val |= b1_get_byte(base); | ||
247 | val |= (b1_get_byte(base) << 8); | ||
248 | val |= (b1_get_byte(base) << 16); | ||
249 | val |= (b1_get_byte(base) << 24); | ||
250 | return val; | ||
251 | } | ||
252 | |||
253 | static inline int b1_tx_empty(unsigned int base) | ||
254 | { | ||
255 | return inb(base + B1_OUTSTAT) & 0x1; | ||
256 | } | ||
257 | |||
258 | static inline void b1_put_byte(unsigned int base, unsigned char val) | ||
259 | { | ||
260 | while (!b1_tx_empty(base)); | ||
261 | b1outp(base, B1_WRITE, val); | ||
262 | } | ||
263 | |||
264 | static inline int b1_save_put_byte(unsigned int base, unsigned char val) | ||
265 | { | ||
266 | unsigned long stop = jiffies + 2 * HZ; | ||
267 | while (!b1_tx_empty(base) && time_before(jiffies,stop)); | ||
268 | if (!b1_tx_empty(base)) return -1; | ||
269 | b1outp(base, B1_WRITE, val); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static inline void b1_put_word(unsigned int base, unsigned int val) | ||
274 | { | ||
275 | b1_put_byte(base, val & 0xff); | ||
276 | b1_put_byte(base, (val >> 8) & 0xff); | ||
277 | b1_put_byte(base, (val >> 16) & 0xff); | ||
278 | b1_put_byte(base, (val >> 24) & 0xff); | ||
279 | } | ||
280 | |||
281 | static inline unsigned int b1_get_slice(unsigned int base, | ||
282 | unsigned char *dp) | ||
283 | { | ||
284 | unsigned int len, i; | ||
285 | |||
286 | len = i = b1_get_word(base); | ||
287 | while (i-- > 0) *dp++ = b1_get_byte(base); | ||
288 | return len; | ||
289 | } | ||
290 | |||
291 | static inline void b1_put_slice(unsigned int base, | ||
292 | unsigned char *dp, unsigned int len) | ||
293 | { | ||
294 | unsigned i = len; | ||
295 | b1_put_word(base, i); | ||
296 | while (i-- > 0) | ||
297 | b1_put_byte(base, *dp++); | ||
298 | } | ||
299 | |||
300 | static void b1_wr_reg(unsigned int base, | ||
301 | unsigned int reg, | ||
302 | unsigned int value) | ||
303 | { | ||
304 | b1_put_byte(base, WRITE_REGISTER); | ||
305 | b1_put_word(base, reg); | ||
306 | b1_put_word(base, value); | ||
307 | } | ||
308 | |||
309 | static inline unsigned int b1_rd_reg(unsigned int base, | ||
310 | unsigned int reg) | ||
311 | { | ||
312 | b1_put_byte(base, READ_REGISTER); | ||
313 | b1_put_word(base, reg); | ||
314 | return b1_get_word(base); | ||
315 | |||
316 | } | ||
317 | |||
318 | static inline void b1_reset(unsigned int base) | ||
319 | { | ||
320 | b1outp(base, B1_RESET, 0); | ||
321 | mdelay(55 * 2); /* 2 TIC's */ | ||
322 | |||
323 | b1outp(base, B1_RESET, 1); | ||
324 | mdelay(55 * 2); /* 2 TIC's */ | ||
325 | |||
326 | b1outp(base, B1_RESET, 0); | ||
327 | mdelay(55 * 2); /* 2 TIC's */ | ||
328 | } | ||
329 | |||
330 | static inline unsigned char b1_disable_irq(unsigned int base) | ||
331 | { | ||
332 | return b1outp(base, B1_INSTAT, 0x00); | ||
333 | } | ||
334 | |||
335 | /* ---------------------------------------------------------------- */ | ||
336 | |||
337 | static inline void b1_set_test_bit(unsigned int base, | ||
338 | enum avmcardtype cardtype, | ||
339 | int onoff) | ||
340 | { | ||
341 | b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20); | ||
342 | } | ||
343 | |||
344 | static inline int b1_get_test_bit(unsigned int base, | ||
345 | enum avmcardtype cardtype) | ||
346 | { | ||
347 | return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0; | ||
348 | } | ||
349 | |||
350 | /* ---------------------------------------------------------------- */ | ||
351 | |||
352 | #define T1_FASTLINK 0x00 | ||
353 | #define T1_SLOWLINK 0x08 | ||
354 | |||
355 | #define T1_READ B1_READ | ||
356 | #define T1_WRITE B1_WRITE | ||
357 | #define T1_INSTAT B1_INSTAT | ||
358 | #define T1_OUTSTAT B1_OUTSTAT | ||
359 | #define T1_IRQENABLE 0x05 | ||
360 | #define T1_FIFOSTAT 0x06 | ||
361 | #define T1_RESETLINK 0x10 | ||
362 | #define T1_ANALYSE 0x11 | ||
363 | #define T1_IRQMASTER 0x12 | ||
364 | #define T1_IDENT 0x17 | ||
365 | #define T1_RESETBOARD 0x1f | ||
366 | |||
367 | #define T1F_IREADY 0x01 | ||
368 | #define T1F_IHALF 0x02 | ||
369 | #define T1F_IFULL 0x04 | ||
370 | #define T1F_IEMPTY 0x08 | ||
371 | #define T1F_IFLAGS 0xF0 | ||
372 | |||
373 | #define T1F_OREADY 0x10 | ||
374 | #define T1F_OHALF 0x20 | ||
375 | #define T1F_OEMPTY 0x40 | ||
376 | #define T1F_OFULL 0x80 | ||
377 | #define T1F_OFLAGS 0xF0 | ||
378 | |||
379 | /* there are HEMA cards with 1k and 4k FIFO out */ | ||
380 | #define FIFO_OUTBSIZE 256 | ||
381 | #define FIFO_INPBSIZE 512 | ||
382 | |||
383 | #define HEMA_VERSION_ID 0 | ||
384 | #define HEMA_PAL_ID 0 | ||
385 | |||
386 | static inline void t1outp(unsigned int base, | ||
387 | unsigned short offset, | ||
388 | unsigned char value) | ||
389 | { | ||
390 | outb(value, base + offset); | ||
391 | } | ||
392 | |||
393 | static inline unsigned char t1inp(unsigned int base, | ||
394 | unsigned short offset) | ||
395 | { | ||
396 | return inb(base + offset); | ||
397 | } | ||
398 | |||
399 | static inline int t1_isfastlink(unsigned int base) | ||
400 | { | ||
401 | return (inb(base + T1_IDENT) & ~0x82) == 1; | ||
402 | } | ||
403 | |||
404 | static inline unsigned char t1_fifostatus(unsigned int base) | ||
405 | { | ||
406 | return inb(base + T1_FIFOSTAT); | ||
407 | } | ||
408 | |||
409 | static inline unsigned int t1_get_slice(unsigned int base, | ||
410 | unsigned char *dp) | ||
411 | { | ||
412 | unsigned int len, i; | ||
413 | #ifdef FASTLINK_DEBUG | ||
414 | unsigned wcnt = 0, bcnt = 0; | ||
415 | #endif | ||
416 | |||
417 | len = i = b1_get_word(base); | ||
418 | if (t1_isfastlink(base)) { | ||
419 | int status; | ||
420 | while (i > 0) { | ||
421 | status = t1_fifostatus(base) & (T1F_IREADY|T1F_IHALF); | ||
422 | if (i >= FIFO_INPBSIZE) status |= T1F_IFULL; | ||
423 | |||
424 | switch (status) { | ||
425 | case T1F_IREADY|T1F_IHALF|T1F_IFULL: | ||
426 | insb(base+B1_READ, dp, FIFO_INPBSIZE); | ||
427 | dp += FIFO_INPBSIZE; | ||
428 | i -= FIFO_INPBSIZE; | ||
429 | #ifdef FASTLINK_DEBUG | ||
430 | wcnt += FIFO_INPBSIZE; | ||
431 | #endif | ||
432 | break; | ||
433 | case T1F_IREADY|T1F_IHALF: | ||
434 | insb(base+B1_READ,dp, i); | ||
435 | #ifdef FASTLINK_DEBUG | ||
436 | wcnt += i; | ||
437 | #endif | ||
438 | dp += i; | ||
439 | i = 0; | ||
440 | if (i == 0) | ||
441 | break; | ||
442 | /* fall through */ | ||
443 | default: | ||
444 | *dp++ = b1_get_byte(base); | ||
445 | i--; | ||
446 | #ifdef FASTLINK_DEBUG | ||
447 | bcnt++; | ||
448 | #endif | ||
449 | break; | ||
450 | } | ||
451 | } | ||
452 | #ifdef FASTLINK_DEBUG | ||
453 | if (wcnt) | ||
454 | printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n", | ||
455 | base, len, wcnt, bcnt); | ||
456 | #endif | ||
457 | } else { | ||
458 | while (i-- > 0) | ||
459 | *dp++ = b1_get_byte(base); | ||
460 | } | ||
461 | return len; | ||
462 | } | ||
463 | |||
464 | static inline void t1_put_slice(unsigned int base, | ||
465 | unsigned char *dp, unsigned int len) | ||
466 | { | ||
467 | unsigned i = len; | ||
468 | b1_put_word(base, i); | ||
469 | if (t1_isfastlink(base)) { | ||
470 | int status; | ||
471 | while (i > 0) { | ||
472 | status = t1_fifostatus(base) & (T1F_OREADY|T1F_OHALF); | ||
473 | if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY; | ||
474 | switch (status) { | ||
475 | case T1F_OREADY|T1F_OHALF|T1F_OEMPTY: | ||
476 | outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE); | ||
477 | dp += FIFO_OUTBSIZE; | ||
478 | i -= FIFO_OUTBSIZE; | ||
479 | break; | ||
480 | case T1F_OREADY|T1F_OHALF: | ||
481 | outsb(base+B1_WRITE, dp, i); | ||
482 | dp += i; | ||
483 | i = 0; | ||
484 | break; | ||
485 | default: | ||
486 | b1_put_byte(base, *dp++); | ||
487 | i--; | ||
488 | break; | ||
489 | } | ||
490 | } | ||
491 | } else { | ||
492 | while (i-- > 0) | ||
493 | b1_put_byte(base, *dp++); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static inline void t1_disable_irq(unsigned int base) | ||
498 | { | ||
499 | t1outp(base, T1_IRQMASTER, 0x00); | ||
500 | } | ||
501 | |||
502 | static inline void t1_reset(unsigned int base) | ||
503 | { | ||
504 | /* reset T1 Controller */ | ||
505 | b1_reset(base); | ||
506 | /* disable irq on HEMA */ | ||
507 | t1outp(base, B1_INSTAT, 0x00); | ||
508 | t1outp(base, B1_OUTSTAT, 0x00); | ||
509 | t1outp(base, T1_IRQMASTER, 0x00); | ||
510 | /* reset HEMA board configuration */ | ||
511 | t1outp(base, T1_RESETBOARD, 0xf); | ||
512 | } | ||
513 | |||
514 | static inline void b1_setinterrupt(unsigned int base, unsigned irq, | ||
515 | enum avmcardtype cardtype) | ||
516 | { | ||
517 | switch (cardtype) { | ||
518 | case avm_t1isa: | ||
519 | t1outp(base, B1_INSTAT, 0x00); | ||
520 | t1outp(base, B1_INSTAT, 0x02); | ||
521 | t1outp(base, T1_IRQMASTER, 0x08); | ||
522 | break; | ||
523 | case avm_b1isa: | ||
524 | b1outp(base, B1_INSTAT, 0x00); | ||
525 | b1outp(base, B1_RESET, b1_irq_table[irq]); | ||
526 | b1outp(base, B1_INSTAT, 0x02); | ||
527 | break; | ||
528 | default: | ||
529 | case avm_m1: | ||
530 | case avm_m2: | ||
531 | case avm_b1pci: | ||
532 | b1outp(base, B1_INSTAT, 0x00); | ||
533 | b1outp(base, B1_RESET, 0xf0); | ||
534 | b1outp(base, B1_INSTAT, 0x02); | ||
535 | break; | ||
536 | case avm_c4: | ||
537 | case avm_t1pci: | ||
538 | b1outp(base, B1_RESET, 0xf0); | ||
539 | break; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | /* b1.c */ | ||
544 | avmcard *b1_alloc_card(int nr_controllers); | ||
545 | void b1_free_card(avmcard *card); | ||
546 | int b1_detect(unsigned int base, enum avmcardtype cardtype); | ||
547 | void b1_getrevision(avmcard *card); | ||
548 | int b1_load_t4file(avmcard *card, capiloaddatapart * t4file); | ||
549 | int b1_load_config(avmcard *card, capiloaddatapart * config); | ||
550 | int b1_loaded(avmcard *card); | ||
551 | |||
552 | int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); | ||
553 | void b1_reset_ctr(struct capi_ctr *ctrl); | ||
554 | void b1_register_appl(struct capi_ctr *ctrl, u16 appl, | ||
555 | capi_register_params *rp); | ||
556 | void b1_release_appl(struct capi_ctr *ctrl, u16 appl); | ||
557 | u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); | ||
558 | void b1_parse_version(avmctrl_info *card); | ||
559 | irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs); | ||
560 | |||
561 | int b1ctl_read_proc(char *page, char **start, off_t off, | ||
562 | int count, int *eof, struct capi_ctr *ctrl); | ||
563 | |||
564 | avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *, | ||
565 | long rsize, long ssize); | ||
566 | void avmcard_dma_free(avmcard_dmainfo *); | ||
567 | |||
568 | /* b1dma.c */ | ||
569 | int b1pciv4_detect(avmcard *card); | ||
570 | int t1pci_detect(avmcard *card); | ||
571 | void b1dma_reset(avmcard *card); | ||
572 | irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs); | ||
573 | |||
574 | int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); | ||
575 | void b1dma_reset_ctr(struct capi_ctr *ctrl); | ||
576 | void b1dma_remove_ctr(struct capi_ctr *ctrl); | ||
577 | void b1dma_register_appl(struct capi_ctr *ctrl, | ||
578 | u16 appl, | ||
579 | capi_register_params *rp); | ||
580 | void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl); | ||
581 | u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); | ||
582 | int b1dmactl_read_proc(char *page, char **start, off_t off, | ||
583 | int count, int *eof, struct capi_ctr *ctrl); | ||
584 | |||
585 | #endif /* _AVMCARD_H_ */ | ||
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c new file mode 100644 index 000000000000..0c7061d55027 --- /dev/null +++ b/drivers/isdn/hardware/avm/b1.c | |||
@@ -0,0 +1,814 @@ | |||
1 | /* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ | ||
2 | * | ||
3 | * Common module for AVM B1 cards. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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 | #include <linux/kernel.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/capi.h> | ||
21 | #include <linux/kernelcapi.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/isdn/capilli.h> | ||
27 | #include "avmcard.h" | ||
28 | #include <linux/isdn/capicmd.h> | ||
29 | #include <linux/isdn/capiutil.h> | ||
30 | |||
31 | static char *revision = "$Revision: 1.1.2.2 $"; | ||
32 | |||
33 | /* ------------------------------------------------------------- */ | ||
34 | |||
35 | MODULE_DESCRIPTION("CAPI4Linux: Common support for active AVM cards"); | ||
36 | MODULE_AUTHOR("Carsten Paeth"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | /* ------------------------------------------------------------- */ | ||
40 | |||
41 | int b1_irq_table[16] = | ||
42 | {0, | ||
43 | 0, | ||
44 | 0, | ||
45 | 192, /* irq 3 */ | ||
46 | 32, /* irq 4 */ | ||
47 | 160, /* irq 5 */ | ||
48 | 96, /* irq 6 */ | ||
49 | 224, /* irq 7 */ | ||
50 | 0, | ||
51 | 64, /* irq 9 */ | ||
52 | 80, /* irq 10 */ | ||
53 | 208, /* irq 11 */ | ||
54 | 48, /* irq 12 */ | ||
55 | 0, | ||
56 | 0, | ||
57 | 112, /* irq 15 */ | ||
58 | }; | ||
59 | |||
60 | /* ------------------------------------------------------------- */ | ||
61 | |||
62 | avmcard *b1_alloc_card(int nr_controllers) | ||
63 | { | ||
64 | avmcard *card; | ||
65 | avmctrl_info *cinfo; | ||
66 | int i; | ||
67 | |||
68 | card = kmalloc(sizeof(*card), GFP_KERNEL); | ||
69 | if (!card) | ||
70 | return NULL; | ||
71 | |||
72 | memset(card, 0, sizeof(*card)); | ||
73 | |||
74 | cinfo = kmalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL); | ||
75 | if (!cinfo) { | ||
76 | kfree(card); | ||
77 | return NULL; | ||
78 | } | ||
79 | memset(cinfo, 0, sizeof(*cinfo) * nr_controllers); | ||
80 | |||
81 | card->ctrlinfo = cinfo; | ||
82 | for (i = 0; i < nr_controllers; i++) { | ||
83 | INIT_LIST_HEAD(&cinfo[i].ncci_head); | ||
84 | cinfo[i].card = card; | ||
85 | } | ||
86 | spin_lock_init(&card->lock); | ||
87 | card->nr_controllers = nr_controllers; | ||
88 | |||
89 | return card; | ||
90 | } | ||
91 | |||
92 | /* ------------------------------------------------------------- */ | ||
93 | |||
94 | void b1_free_card(avmcard *card) | ||
95 | { | ||
96 | kfree(card->ctrlinfo); | ||
97 | kfree(card); | ||
98 | } | ||
99 | |||
100 | /* ------------------------------------------------------------- */ | ||
101 | |||
102 | int b1_detect(unsigned int base, enum avmcardtype cardtype) | ||
103 | { | ||
104 | int onoff, i; | ||
105 | |||
106 | /* | ||
107 | * Statusregister 0000 00xx | ||
108 | */ | ||
109 | if ((inb(base + B1_INSTAT) & 0xfc) | ||
110 | || (inb(base + B1_OUTSTAT) & 0xfc)) | ||
111 | return 1; | ||
112 | /* | ||
113 | * Statusregister 0000 001x | ||
114 | */ | ||
115 | b1outp(base, B1_INSTAT, 0x2); /* enable irq */ | ||
116 | /* b1outp(base, B1_OUTSTAT, 0x2); */ | ||
117 | if ((inb(base + B1_INSTAT) & 0xfe) != 0x2 | ||
118 | /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */) | ||
119 | return 2; | ||
120 | /* | ||
121 | * Statusregister 0000 000x | ||
122 | */ | ||
123 | b1outp(base, B1_INSTAT, 0x0); /* disable irq */ | ||
124 | b1outp(base, B1_OUTSTAT, 0x0); | ||
125 | if ((inb(base + B1_INSTAT) & 0xfe) | ||
126 | || (inb(base + B1_OUTSTAT) & 0xfe)) | ||
127 | return 3; | ||
128 | |||
129 | for (onoff = !0, i= 0; i < 10 ; i++) { | ||
130 | b1_set_test_bit(base, cardtype, onoff); | ||
131 | if (b1_get_test_bit(base, cardtype) != onoff) | ||
132 | return 4; | ||
133 | onoff = !onoff; | ||
134 | } | ||
135 | |||
136 | if (cardtype == avm_m1) | ||
137 | return 0; | ||
138 | |||
139 | if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01) | ||
140 | return 5; | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | void b1_getrevision(avmcard *card) | ||
146 | { | ||
147 | card->class = inb(card->port + B1_ANALYSE); | ||
148 | card->revision = inb(card->port + B1_REVISION); | ||
149 | } | ||
150 | |||
151 | #define FWBUF_SIZE 256 | ||
152 | int b1_load_t4file(avmcard *card, capiloaddatapart * t4file) | ||
153 | { | ||
154 | unsigned char buf[FWBUF_SIZE]; | ||
155 | unsigned char *dp; | ||
156 | int i, left; | ||
157 | unsigned int base = card->port; | ||
158 | |||
159 | dp = t4file->data; | ||
160 | left = t4file->len; | ||
161 | while (left > FWBUF_SIZE) { | ||
162 | if (t4file->user) { | ||
163 | if (copy_from_user(buf, dp, FWBUF_SIZE)) | ||
164 | return -EFAULT; | ||
165 | } else { | ||
166 | memcpy(buf, dp, FWBUF_SIZE); | ||
167 | } | ||
168 | for (i = 0; i < FWBUF_SIZE; i++) | ||
169 | if (b1_save_put_byte(base, buf[i]) < 0) { | ||
170 | printk(KERN_ERR "%s: corrupted firmware file ?\n", | ||
171 | card->name); | ||
172 | return -EIO; | ||
173 | } | ||
174 | left -= FWBUF_SIZE; | ||
175 | dp += FWBUF_SIZE; | ||
176 | } | ||
177 | if (left) { | ||
178 | if (t4file->user) { | ||
179 | if (copy_from_user(buf, dp, left)) | ||
180 | return -EFAULT; | ||
181 | } else { | ||
182 | memcpy(buf, dp, left); | ||
183 | } | ||
184 | for (i = 0; i < left; i++) | ||
185 | if (b1_save_put_byte(base, buf[i]) < 0) { | ||
186 | printk(KERN_ERR "%s: corrupted firmware file ?\n", | ||
187 | card->name); | ||
188 | return -EIO; | ||
189 | } | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | int b1_load_config(avmcard *card, capiloaddatapart * config) | ||
195 | { | ||
196 | unsigned char buf[FWBUF_SIZE]; | ||
197 | unsigned char *dp; | ||
198 | unsigned int base = card->port; | ||
199 | int i, j, left; | ||
200 | |||
201 | dp = config->data; | ||
202 | left = config->len; | ||
203 | if (left) { | ||
204 | b1_put_byte(base, SEND_CONFIG); | ||
205 | b1_put_word(base, 1); | ||
206 | b1_put_byte(base, SEND_CONFIG); | ||
207 | b1_put_word(base, left); | ||
208 | } | ||
209 | while (left > FWBUF_SIZE) { | ||
210 | if (config->user) { | ||
211 | if (copy_from_user(buf, dp, FWBUF_SIZE)) | ||
212 | return -EFAULT; | ||
213 | } else { | ||
214 | memcpy(buf, dp, FWBUF_SIZE); | ||
215 | } | ||
216 | for (i = 0; i < FWBUF_SIZE; ) { | ||
217 | b1_put_byte(base, SEND_CONFIG); | ||
218 | for (j=0; j < 4; j++) { | ||
219 | b1_put_byte(base, buf[i++]); | ||
220 | } | ||
221 | } | ||
222 | left -= FWBUF_SIZE; | ||
223 | dp += FWBUF_SIZE; | ||
224 | } | ||
225 | if (left) { | ||
226 | if (config->user) { | ||
227 | if (copy_from_user(buf, dp, left)) | ||
228 | return -EFAULT; | ||
229 | } else { | ||
230 | memcpy(buf, dp, left); | ||
231 | } | ||
232 | for (i = 0; i < left; ) { | ||
233 | b1_put_byte(base, SEND_CONFIG); | ||
234 | for (j=0; j < 4; j++) { | ||
235 | if (i < left) | ||
236 | b1_put_byte(base, buf[i++]); | ||
237 | else | ||
238 | b1_put_byte(base, 0); | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | int b1_loaded(avmcard *card) | ||
246 | { | ||
247 | unsigned int base = card->port; | ||
248 | unsigned long stop; | ||
249 | unsigned char ans; | ||
250 | unsigned long tout = 2; | ||
251 | |||
252 | for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { | ||
253 | if (b1_tx_empty(base)) | ||
254 | break; | ||
255 | } | ||
256 | if (!b1_tx_empty(base)) { | ||
257 | printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n", | ||
258 | card->name); | ||
259 | return 0; | ||
260 | } | ||
261 | b1_put_byte(base, SEND_POLL); | ||
262 | for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { | ||
263 | if (b1_rx_full(base)) { | ||
264 | if ((ans = b1_get_byte(base)) == RECEIVE_POLL) { | ||
265 | return 1; | ||
266 | } | ||
267 | printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n", | ||
268 | card->name, ans); | ||
269 | return 0; | ||
270 | } | ||
271 | } | ||
272 | printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* ------------------------------------------------------------- */ | ||
277 | |||
278 | int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) | ||
279 | { | ||
280 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
281 | avmcard *card = cinfo->card; | ||
282 | unsigned int port = card->port; | ||
283 | unsigned long flags; | ||
284 | int retval; | ||
285 | |||
286 | b1_reset(port); | ||
287 | |||
288 | if ((retval = b1_load_t4file(card, &data->firmware))) { | ||
289 | b1_reset(port); | ||
290 | printk(KERN_ERR "%s: failed to load t4file!!\n", | ||
291 | card->name); | ||
292 | return retval; | ||
293 | } | ||
294 | |||
295 | b1_disable_irq(port); | ||
296 | |||
297 | if (data->configuration.len > 0 && data->configuration.data) { | ||
298 | if ((retval = b1_load_config(card, &data->configuration))) { | ||
299 | b1_reset(port); | ||
300 | printk(KERN_ERR "%s: failed to load config!!\n", | ||
301 | card->name); | ||
302 | return retval; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | if (!b1_loaded(card)) { | ||
307 | printk(KERN_ERR "%s: failed to load t4file.\n", card->name); | ||
308 | return -EIO; | ||
309 | } | ||
310 | |||
311 | spin_lock_irqsave(&card->lock, flags); | ||
312 | b1_setinterrupt(port, card->irq, card->cardtype); | ||
313 | b1_put_byte(port, SEND_INIT); | ||
314 | b1_put_word(port, CAPI_MAXAPPL); | ||
315 | b1_put_word(port, AVM_NCCI_PER_CHANNEL*2); | ||
316 | b1_put_word(port, ctrl->cnr - 1); | ||
317 | spin_unlock_irqrestore(&card->lock, flags); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | void b1_reset_ctr(struct capi_ctr *ctrl) | ||
323 | { | ||
324 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
325 | avmcard *card = cinfo->card; | ||
326 | unsigned int port = card->port; | ||
327 | |||
328 | b1_reset(port); | ||
329 | b1_reset(port); | ||
330 | |||
331 | memset(cinfo->version, 0, sizeof(cinfo->version)); | ||
332 | capilib_release(&cinfo->ncci_head); | ||
333 | capi_ctr_reseted(ctrl); | ||
334 | } | ||
335 | |||
336 | void b1_register_appl(struct capi_ctr *ctrl, | ||
337 | u16 appl, | ||
338 | capi_register_params *rp) | ||
339 | { | ||
340 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
341 | avmcard *card = cinfo->card; | ||
342 | unsigned int port = card->port; | ||
343 | unsigned long flags; | ||
344 | int nconn, want = rp->level3cnt; | ||
345 | |||
346 | if (want > 0) nconn = want; | ||
347 | else nconn = ctrl->profile.nbchannel * -want; | ||
348 | if (nconn == 0) nconn = ctrl->profile.nbchannel; | ||
349 | |||
350 | spin_lock_irqsave(&card->lock, flags); | ||
351 | b1_put_byte(port, SEND_REGISTER); | ||
352 | b1_put_word(port, appl); | ||
353 | b1_put_word(port, 1024 * (nconn+1)); | ||
354 | b1_put_word(port, nconn); | ||
355 | b1_put_word(port, rp->datablkcnt); | ||
356 | b1_put_word(port, rp->datablklen); | ||
357 | spin_unlock_irqrestore(&card->lock, flags); | ||
358 | } | ||
359 | |||
360 | void b1_release_appl(struct capi_ctr *ctrl, u16 appl) | ||
361 | { | ||
362 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
363 | avmcard *card = cinfo->card; | ||
364 | unsigned int port = card->port; | ||
365 | unsigned long flags; | ||
366 | |||
367 | capilib_release_appl(&cinfo->ncci_head, appl); | ||
368 | |||
369 | spin_lock_irqsave(&card->lock, flags); | ||
370 | b1_put_byte(port, SEND_RELEASE); | ||
371 | b1_put_word(port, appl); | ||
372 | spin_unlock_irqrestore(&card->lock, flags); | ||
373 | } | ||
374 | |||
375 | u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | ||
376 | { | ||
377 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
378 | avmcard *card = cinfo->card; | ||
379 | unsigned int port = card->port; | ||
380 | unsigned long flags; | ||
381 | u16 len = CAPIMSG_LEN(skb->data); | ||
382 | u8 cmd = CAPIMSG_COMMAND(skb->data); | ||
383 | u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); | ||
384 | u16 dlen, retval; | ||
385 | |||
386 | if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { | ||
387 | retval = capilib_data_b3_req(&cinfo->ncci_head, | ||
388 | CAPIMSG_APPID(skb->data), | ||
389 | CAPIMSG_NCCI(skb->data), | ||
390 | CAPIMSG_MSGID(skb->data)); | ||
391 | if (retval != CAPI_NOERROR) | ||
392 | return retval; | ||
393 | |||
394 | dlen = CAPIMSG_DATALEN(skb->data); | ||
395 | |||
396 | spin_lock_irqsave(&card->lock, flags); | ||
397 | b1_put_byte(port, SEND_DATA_B3_REQ); | ||
398 | b1_put_slice(port, skb->data, len); | ||
399 | b1_put_slice(port, skb->data + len, dlen); | ||
400 | spin_unlock_irqrestore(&card->lock, flags); | ||
401 | } else { | ||
402 | spin_lock_irqsave(&card->lock, flags); | ||
403 | b1_put_byte(port, SEND_MESSAGE); | ||
404 | b1_put_slice(port, skb->data, len); | ||
405 | spin_unlock_irqrestore(&card->lock, flags); | ||
406 | } | ||
407 | |||
408 | dev_kfree_skb_any(skb); | ||
409 | return CAPI_NOERROR; | ||
410 | } | ||
411 | |||
412 | /* ------------------------------------------------------------- */ | ||
413 | |||
414 | void b1_parse_version(avmctrl_info *cinfo) | ||
415 | { | ||
416 | struct capi_ctr *ctrl = &cinfo->capi_ctrl; | ||
417 | avmcard *card = cinfo->card; | ||
418 | capi_profile *profp; | ||
419 | u8 *dversion; | ||
420 | u8 flag; | ||
421 | int i, j; | ||
422 | |||
423 | for (j = 0; j < AVM_MAXVERSION; j++) | ||
424 | cinfo->version[j] = "\0\0" + 1; | ||
425 | for (i = 0, j = 0; | ||
426 | j < AVM_MAXVERSION && i < cinfo->versionlen; | ||
427 | j++, i += cinfo->versionbuf[i] + 1) | ||
428 | cinfo->version[j] = &cinfo->versionbuf[i + 1]; | ||
429 | |||
430 | strlcpy(ctrl->serial, cinfo->version[VER_SERIAL], sizeof(ctrl->serial)); | ||
431 | memcpy(&ctrl->profile, cinfo->version[VER_PROFILE],sizeof(capi_profile)); | ||
432 | strlcpy(ctrl->manu, "AVM GmbH", sizeof(ctrl->manu)); | ||
433 | dversion = cinfo->version[VER_DRIVER]; | ||
434 | ctrl->version.majorversion = 2; | ||
435 | ctrl->version.minorversion = 0; | ||
436 | ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4); | ||
437 | ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf); | ||
438 | ctrl->version.minormanuversion = (dversion[3] - '0') << 4; | ||
439 | ctrl->version.minormanuversion |= | ||
440 | (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf); | ||
441 | |||
442 | profp = &ctrl->profile; | ||
443 | |||
444 | flag = ((u8 *)(profp->manu))[1]; | ||
445 | switch (flag) { | ||
446 | case 0: if (cinfo->version[VER_CARDTYPE]) | ||
447 | strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]); | ||
448 | else strcpy(cinfo->cardname, "B1"); | ||
449 | break; | ||
450 | case 3: strcpy(cinfo->cardname,"PCMCIA B"); break; | ||
451 | case 4: strcpy(cinfo->cardname,"PCMCIA M1"); break; | ||
452 | case 5: strcpy(cinfo->cardname,"PCMCIA M2"); break; | ||
453 | case 6: strcpy(cinfo->cardname,"B1 V3.0"); break; | ||
454 | case 7: strcpy(cinfo->cardname,"B1 PCI"); break; | ||
455 | default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break; | ||
456 | } | ||
457 | printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n", | ||
458 | card->name, ctrl->cnr, cinfo->cardname); | ||
459 | |||
460 | flag = ((u8 *)(profp->manu))[3]; | ||
461 | if (flag) | ||
462 | printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n", | ||
463 | card->name, | ||
464 | ctrl->cnr, | ||
465 | (flag & 0x01) ? " DSS1" : "", | ||
466 | (flag & 0x02) ? " CT1" : "", | ||
467 | (flag & 0x04) ? " VN3" : "", | ||
468 | (flag & 0x08) ? " NI1" : "", | ||
469 | (flag & 0x10) ? " AUSTEL" : "", | ||
470 | (flag & 0x20) ? " ESS" : "", | ||
471 | (flag & 0x40) ? " 1TR6" : "" | ||
472 | ); | ||
473 | |||
474 | flag = ((u8 *)(profp->manu))[5]; | ||
475 | if (flag) | ||
476 | printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n", | ||
477 | card->name, | ||
478 | ctrl->cnr, | ||
479 | (flag & 0x01) ? " point to point" : "", | ||
480 | (flag & 0x02) ? " point to multipoint" : "", | ||
481 | (flag & 0x08) ? " leased line without D-channel" : "", | ||
482 | (flag & 0x04) ? " leased line with D-channel" : "" | ||
483 | ); | ||
484 | } | ||
485 | |||
486 | /* ------------------------------------------------------------- */ | ||
487 | |||
488 | irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs) | ||
489 | { | ||
490 | avmcard *card = devptr; | ||
491 | avmctrl_info *cinfo = &card->ctrlinfo[0]; | ||
492 | struct capi_ctr *ctrl = &cinfo->capi_ctrl; | ||
493 | unsigned char b1cmd; | ||
494 | struct sk_buff *skb; | ||
495 | |||
496 | unsigned ApplId; | ||
497 | unsigned MsgLen; | ||
498 | unsigned DataB3Len; | ||
499 | unsigned NCCI; | ||
500 | unsigned WindowSize; | ||
501 | unsigned long flags; | ||
502 | |||
503 | spin_lock_irqsave(&card->lock, flags); | ||
504 | |||
505 | if (!b1_rx_full(card->port)) { | ||
506 | spin_unlock_irqrestore(&card->lock, flags); | ||
507 | return IRQ_NONE; | ||
508 | } | ||
509 | |||
510 | b1cmd = b1_get_byte(card->port); | ||
511 | |||
512 | switch (b1cmd) { | ||
513 | |||
514 | case RECEIVE_DATA_B3_IND: | ||
515 | |||
516 | ApplId = (unsigned) b1_get_word(card->port); | ||
517 | MsgLen = b1_get_slice(card->port, card->msgbuf); | ||
518 | DataB3Len = b1_get_slice(card->port, card->databuf); | ||
519 | spin_unlock_irqrestore(&card->lock, flags); | ||
520 | |||
521 | if (MsgLen < 30) { /* not CAPI 64Bit */ | ||
522 | memset(card->msgbuf+MsgLen, 0, 30-MsgLen); | ||
523 | MsgLen = 30; | ||
524 | CAPIMSG_SETLEN(card->msgbuf, 30); | ||
525 | } | ||
526 | if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { | ||
527 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
528 | card->name); | ||
529 | } else { | ||
530 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
531 | memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); | ||
532 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
533 | } | ||
534 | break; | ||
535 | |||
536 | case RECEIVE_MESSAGE: | ||
537 | |||
538 | ApplId = (unsigned) b1_get_word(card->port); | ||
539 | MsgLen = b1_get_slice(card->port, card->msgbuf); | ||
540 | spin_unlock_irqrestore(&card->lock, flags); | ||
541 | if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { | ||
542 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
543 | card->name); | ||
544 | } else { | ||
545 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
546 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) | ||
547 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | ||
548 | CAPIMSG_NCCI(skb->data), | ||
549 | CAPIMSG_MSGID(skb->data)); | ||
550 | |||
551 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
552 | } | ||
553 | break; | ||
554 | |||
555 | case RECEIVE_NEW_NCCI: | ||
556 | |||
557 | ApplId = b1_get_word(card->port); | ||
558 | NCCI = b1_get_word(card->port); | ||
559 | WindowSize = b1_get_word(card->port); | ||
560 | spin_unlock_irqrestore(&card->lock, flags); | ||
561 | |||
562 | capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); | ||
563 | |||
564 | break; | ||
565 | |||
566 | case RECEIVE_FREE_NCCI: | ||
567 | |||
568 | ApplId = b1_get_word(card->port); | ||
569 | NCCI = b1_get_word(card->port); | ||
570 | spin_unlock_irqrestore(&card->lock, flags); | ||
571 | |||
572 | if (NCCI != 0xffffffff) | ||
573 | capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); | ||
574 | |||
575 | break; | ||
576 | |||
577 | case RECEIVE_START: | ||
578 | /* b1_put_byte(card->port, SEND_POLLACK); */ | ||
579 | spin_unlock_irqrestore(&card->lock, flags); | ||
580 | capi_ctr_resume_output(ctrl); | ||
581 | break; | ||
582 | |||
583 | case RECEIVE_STOP: | ||
584 | spin_unlock_irqrestore(&card->lock, flags); | ||
585 | capi_ctr_suspend_output(ctrl); | ||
586 | break; | ||
587 | |||
588 | case RECEIVE_INIT: | ||
589 | |||
590 | cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf); | ||
591 | spin_unlock_irqrestore(&card->lock, flags); | ||
592 | b1_parse_version(cinfo); | ||
593 | printk(KERN_INFO "%s: %s-card (%s) now active\n", | ||
594 | card->name, | ||
595 | cinfo->version[VER_CARDTYPE], | ||
596 | cinfo->version[VER_DRIVER]); | ||
597 | capi_ctr_ready(ctrl); | ||
598 | break; | ||
599 | |||
600 | case RECEIVE_TASK_READY: | ||
601 | ApplId = (unsigned) b1_get_word(card->port); | ||
602 | MsgLen = b1_get_slice(card->port, card->msgbuf); | ||
603 | spin_unlock_irqrestore(&card->lock, flags); | ||
604 | card->msgbuf[MsgLen] = 0; | ||
605 | while ( MsgLen > 0 | ||
606 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
607 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
608 | card->msgbuf[MsgLen-1] = 0; | ||
609 | MsgLen--; | ||
610 | } | ||
611 | printk(KERN_INFO "%s: task %d \"%s\" ready.\n", | ||
612 | card->name, ApplId, card->msgbuf); | ||
613 | break; | ||
614 | |||
615 | case RECEIVE_DEBUGMSG: | ||
616 | MsgLen = b1_get_slice(card->port, card->msgbuf); | ||
617 | spin_unlock_irqrestore(&card->lock, flags); | ||
618 | card->msgbuf[MsgLen] = 0; | ||
619 | while ( MsgLen > 0 | ||
620 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
621 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
622 | card->msgbuf[MsgLen-1] = 0; | ||
623 | MsgLen--; | ||
624 | } | ||
625 | printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); | ||
626 | break; | ||
627 | |||
628 | case 0xff: | ||
629 | spin_unlock_irqrestore(&card->lock, flags); | ||
630 | printk(KERN_ERR "%s: card removed ?\n", card->name); | ||
631 | return IRQ_NONE; | ||
632 | default: | ||
633 | spin_unlock_irqrestore(&card->lock, flags); | ||
634 | printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", | ||
635 | card->name, b1cmd); | ||
636 | return IRQ_HANDLED; | ||
637 | } | ||
638 | return IRQ_HANDLED; | ||
639 | } | ||
640 | |||
641 | /* ------------------------------------------------------------- */ | ||
642 | int b1ctl_read_proc(char *page, char **start, off_t off, | ||
643 | int count, int *eof, struct capi_ctr *ctrl) | ||
644 | { | ||
645 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
646 | avmcard *card = cinfo->card; | ||
647 | u8 flag; | ||
648 | int len = 0; | ||
649 | char *s; | ||
650 | |||
651 | len += sprintf(page+len, "%-16s %s\n", "name", card->name); | ||
652 | len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); | ||
653 | len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); | ||
654 | switch (card->cardtype) { | ||
655 | case avm_b1isa: s = "B1 ISA"; break; | ||
656 | case avm_b1pci: s = "B1 PCI"; break; | ||
657 | case avm_b1pcmcia: s = "B1 PCMCIA"; break; | ||
658 | case avm_m1: s = "M1"; break; | ||
659 | case avm_m2: s = "M2"; break; | ||
660 | case avm_t1isa: s = "T1 ISA (HEMA)"; break; | ||
661 | case avm_t1pci: s = "T1 PCI"; break; | ||
662 | case avm_c4: s = "C4"; break; | ||
663 | case avm_c2: s = "C2"; break; | ||
664 | default: s = "???"; break; | ||
665 | } | ||
666 | len += sprintf(page+len, "%-16s %s\n", "type", s); | ||
667 | if (card->cardtype == avm_t1isa) | ||
668 | len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr); | ||
669 | if ((s = cinfo->version[VER_DRIVER]) != 0) | ||
670 | len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); | ||
671 | if ((s = cinfo->version[VER_CARDTYPE]) != 0) | ||
672 | len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); | ||
673 | if ((s = cinfo->version[VER_SERIAL]) != 0) | ||
674 | len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); | ||
675 | |||
676 | if (card->cardtype != avm_m1) { | ||
677 | flag = ((u8 *)(ctrl->profile.manu))[3]; | ||
678 | if (flag) | ||
679 | len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", | ||
680 | "protocol", | ||
681 | (flag & 0x01) ? " DSS1" : "", | ||
682 | (flag & 0x02) ? " CT1" : "", | ||
683 | (flag & 0x04) ? " VN3" : "", | ||
684 | (flag & 0x08) ? " NI1" : "", | ||
685 | (flag & 0x10) ? " AUSTEL" : "", | ||
686 | (flag & 0x20) ? " ESS" : "", | ||
687 | (flag & 0x40) ? " 1TR6" : "" | ||
688 | ); | ||
689 | } | ||
690 | if (card->cardtype != avm_m1) { | ||
691 | flag = ((u8 *)(ctrl->profile.manu))[5]; | ||
692 | if (flag) | ||
693 | len += sprintf(page+len, "%-16s%s%s%s%s\n", | ||
694 | "linetype", | ||
695 | (flag & 0x01) ? " point to point" : "", | ||
696 | (flag & 0x02) ? " point to multipoint" : "", | ||
697 | (flag & 0x08) ? " leased line without D-channel" : "", | ||
698 | (flag & 0x04) ? " leased line with D-channel" : "" | ||
699 | ); | ||
700 | } | ||
701 | len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); | ||
702 | |||
703 | if (off+count >= len) | ||
704 | *eof = 1; | ||
705 | if (len < off) | ||
706 | return 0; | ||
707 | *start = page + off; | ||
708 | return ((count < len-off) ? count : len-off); | ||
709 | } | ||
710 | |||
711 | /* ------------------------------------------------------------- */ | ||
712 | |||
713 | #ifdef CONFIG_PCI | ||
714 | |||
715 | avmcard_dmainfo * | ||
716 | avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize) | ||
717 | { | ||
718 | avmcard_dmainfo *p; | ||
719 | void *buf; | ||
720 | |||
721 | p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL); | ||
722 | if (!p) { | ||
723 | printk(KERN_WARNING "%s: no memory.\n", name); | ||
724 | goto err; | ||
725 | } | ||
726 | memset(p, 0, sizeof(avmcard_dmainfo)); | ||
727 | |||
728 | p->recvbuf.size = rsize; | ||
729 | buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr); | ||
730 | if (!buf) { | ||
731 | printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name); | ||
732 | goto err_kfree; | ||
733 | } | ||
734 | p->recvbuf.dmabuf = buf; | ||
735 | |||
736 | p->sendbuf.size = ssize; | ||
737 | buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr); | ||
738 | if (!buf) { | ||
739 | printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name); | ||
740 | goto err_free_consistent; | ||
741 | } | ||
742 | |||
743 | p->sendbuf.dmabuf = buf; | ||
744 | skb_queue_head_init(&p->send_queue); | ||
745 | |||
746 | return p; | ||
747 | |||
748 | err_free_consistent: | ||
749 | pci_free_consistent(p->pcidev, p->recvbuf.size, | ||
750 | p->recvbuf.dmabuf, p->recvbuf.dmaaddr); | ||
751 | err_kfree: | ||
752 | kfree(p); | ||
753 | err: | ||
754 | return NULL; | ||
755 | } | ||
756 | |||
757 | void avmcard_dma_free(avmcard_dmainfo *p) | ||
758 | { | ||
759 | pci_free_consistent(p->pcidev, p->recvbuf.size, | ||
760 | p->recvbuf.dmabuf, p->recvbuf.dmaaddr); | ||
761 | pci_free_consistent(p->pcidev, p->sendbuf.size, | ||
762 | p->sendbuf.dmabuf, p->sendbuf.dmaaddr); | ||
763 | skb_queue_purge(&p->send_queue); | ||
764 | kfree(p); | ||
765 | } | ||
766 | |||
767 | EXPORT_SYMBOL(avmcard_dma_alloc); | ||
768 | EXPORT_SYMBOL(avmcard_dma_free); | ||
769 | |||
770 | #endif | ||
771 | |||
772 | EXPORT_SYMBOL(b1_irq_table); | ||
773 | |||
774 | EXPORT_SYMBOL(b1_alloc_card); | ||
775 | EXPORT_SYMBOL(b1_free_card); | ||
776 | EXPORT_SYMBOL(b1_detect); | ||
777 | EXPORT_SYMBOL(b1_getrevision); | ||
778 | EXPORT_SYMBOL(b1_load_t4file); | ||
779 | EXPORT_SYMBOL(b1_load_config); | ||
780 | EXPORT_SYMBOL(b1_loaded); | ||
781 | EXPORT_SYMBOL(b1_load_firmware); | ||
782 | EXPORT_SYMBOL(b1_reset_ctr); | ||
783 | EXPORT_SYMBOL(b1_register_appl); | ||
784 | EXPORT_SYMBOL(b1_release_appl); | ||
785 | EXPORT_SYMBOL(b1_send_message); | ||
786 | |||
787 | EXPORT_SYMBOL(b1_parse_version); | ||
788 | EXPORT_SYMBOL(b1_interrupt); | ||
789 | |||
790 | EXPORT_SYMBOL(b1ctl_read_proc); | ||
791 | |||
792 | static int __init b1_init(void) | ||
793 | { | ||
794 | char *p; | ||
795 | char rev[32]; | ||
796 | |||
797 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
798 | strlcpy(rev, p + 2, 32); | ||
799 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
800 | *(p-1) = 0; | ||
801 | } else | ||
802 | strcpy(rev, "1.0"); | ||
803 | |||
804 | printk(KERN_INFO "b1: revision %s\n", rev); | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static void __exit b1_exit(void) | ||
810 | { | ||
811 | } | ||
812 | |||
813 | module_init(b1_init); | ||
814 | module_exit(b1_exit); | ||
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c new file mode 100644 index 000000000000..55bed00ca865 --- /dev/null +++ b/drivers/isdn/hardware/avm/b1dma.c | |||
@@ -0,0 +1,980 @@ | |||
1 | /* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ | ||
2 | * | ||
3 | * Common module for AVM B1 cards that support dma with AMCC | ||
4 | * | ||
5 | * Copyright 2000 by Carsten Paeth <calle@calle.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/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/capi.h> | ||
21 | #include <linux/kernelcapi.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/isdn/capilli.h> | ||
27 | #include "avmcard.h" | ||
28 | #include <linux/isdn/capicmd.h> | ||
29 | #include <linux/isdn/capiutil.h> | ||
30 | |||
31 | static char *revision = "$Revision: 1.1.2.3 $"; | ||
32 | |||
33 | #undef CONFIG_B1DMA_DEBUG | ||
34 | |||
35 | /* ------------------------------------------------------------- */ | ||
36 | |||
37 | MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards"); | ||
38 | MODULE_AUTHOR("Carsten Paeth"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | static int suppress_pollack = 0; | ||
42 | MODULE_PARM(suppress_pollack, "0-1i"); | ||
43 | |||
44 | /* ------------------------------------------------------------- */ | ||
45 | |||
46 | static void b1dma_dispatch_tx(avmcard *card); | ||
47 | |||
48 | /* ------------------------------------------------------------- */ | ||
49 | |||
50 | /* S5933 */ | ||
51 | |||
52 | #define AMCC_RXPTR 0x24 | ||
53 | #define AMCC_RXLEN 0x28 | ||
54 | #define AMCC_TXPTR 0x2c | ||
55 | #define AMCC_TXLEN 0x30 | ||
56 | |||
57 | #define AMCC_INTCSR 0x38 | ||
58 | # define EN_READ_TC_INT 0x00008000L | ||
59 | # define EN_WRITE_TC_INT 0x00004000L | ||
60 | # define EN_TX_TC_INT EN_READ_TC_INT | ||
61 | # define EN_RX_TC_INT EN_WRITE_TC_INT | ||
62 | # define AVM_FLAG 0x30000000L | ||
63 | |||
64 | # define ANY_S5933_INT 0x00800000L | ||
65 | # define READ_TC_INT 0x00080000L | ||
66 | # define WRITE_TC_INT 0x00040000L | ||
67 | # define TX_TC_INT READ_TC_INT | ||
68 | # define RX_TC_INT WRITE_TC_INT | ||
69 | # define MASTER_ABORT_INT 0x00100000L | ||
70 | # define TARGET_ABORT_INT 0x00200000L | ||
71 | # define BUS_MASTER_INT 0x00200000L | ||
72 | # define ALL_INT 0x000C0000L | ||
73 | |||
74 | #define AMCC_MCSR 0x3c | ||
75 | # define A2P_HI_PRIORITY 0x00000100L | ||
76 | # define EN_A2P_TRANSFERS 0x00000400L | ||
77 | # define P2A_HI_PRIORITY 0x00001000L | ||
78 | # define EN_P2A_TRANSFERS 0x00004000L | ||
79 | # define RESET_A2P_FLAGS 0x04000000L | ||
80 | # define RESET_P2A_FLAGS 0x02000000L | ||
81 | |||
82 | /* ------------------------------------------------------------- */ | ||
83 | |||
84 | static inline void b1dma_writel(avmcard *card, u32 value, int off) | ||
85 | { | ||
86 | writel(value, card->mbase + off); | ||
87 | } | ||
88 | |||
89 | static inline u32 b1dma_readl(avmcard *card, int off) | ||
90 | { | ||
91 | return readl(card->mbase + off); | ||
92 | } | ||
93 | |||
94 | /* ------------------------------------------------------------- */ | ||
95 | |||
96 | static inline int b1dma_tx_empty(unsigned int port) | ||
97 | { | ||
98 | return inb(port + 0x03) & 0x1; | ||
99 | } | ||
100 | |||
101 | static inline int b1dma_rx_full(unsigned int port) | ||
102 | { | ||
103 | return inb(port + 0x02) & 0x1; | ||
104 | } | ||
105 | |||
106 | static int b1dma_tolink(avmcard *card, void *buf, unsigned int len) | ||
107 | { | ||
108 | unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ | ||
109 | unsigned char *s = (unsigned char *)buf; | ||
110 | while (len--) { | ||
111 | while ( !b1dma_tx_empty(card->port) | ||
112 | && time_before(jiffies, stop)); | ||
113 | if (!b1dma_tx_empty(card->port)) | ||
114 | return -1; | ||
115 | t1outp(card->port, 0x01, *s++); | ||
116 | } | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len) | ||
121 | { | ||
122 | unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ | ||
123 | unsigned char *s = (unsigned char *)buf; | ||
124 | while (len--) { | ||
125 | while ( !b1dma_rx_full(card->port) | ||
126 | && time_before(jiffies, stop)); | ||
127 | if (!b1dma_rx_full(card->port)) | ||
128 | return -1; | ||
129 | *s++ = t1inp(card->port, 0x00); | ||
130 | } | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int WriteReg(avmcard *card, u32 reg, u8 val) | ||
135 | { | ||
136 | u8 cmd = 0x00; | ||
137 | if ( b1dma_tolink(card, &cmd, 1) == 0 | ||
138 | && b1dma_tolink(card, ®, 4) == 0) { | ||
139 | u32 tmp = val; | ||
140 | return b1dma_tolink(card, &tmp, 4); | ||
141 | } | ||
142 | return -1; | ||
143 | } | ||
144 | |||
145 | static u8 ReadReg(avmcard *card, u32 reg) | ||
146 | { | ||
147 | u8 cmd = 0x01; | ||
148 | if ( b1dma_tolink(card, &cmd, 1) == 0 | ||
149 | && b1dma_tolink(card, ®, 4) == 0) { | ||
150 | u32 tmp; | ||
151 | if (b1dma_fromlink(card, &tmp, 4) == 0) | ||
152 | return (u8)tmp; | ||
153 | } | ||
154 | return 0xff; | ||
155 | } | ||
156 | |||
157 | /* ------------------------------------------------------------- */ | ||
158 | |||
159 | static inline void _put_byte(void **pp, u8 val) | ||
160 | { | ||
161 | u8 *s = *pp; | ||
162 | *s++ = val; | ||
163 | *pp = s; | ||
164 | } | ||
165 | |||
166 | static inline void _put_word(void **pp, u32 val) | ||
167 | { | ||
168 | u8 *s = *pp; | ||
169 | *s++ = val & 0xff; | ||
170 | *s++ = (val >> 8) & 0xff; | ||
171 | *s++ = (val >> 16) & 0xff; | ||
172 | *s++ = (val >> 24) & 0xff; | ||
173 | *pp = s; | ||
174 | } | ||
175 | |||
176 | static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) | ||
177 | { | ||
178 | unsigned i = len; | ||
179 | _put_word(pp, i); | ||
180 | while (i-- > 0) | ||
181 | _put_byte(pp, *dp++); | ||
182 | } | ||
183 | |||
184 | static inline u8 _get_byte(void **pp) | ||
185 | { | ||
186 | u8 *s = *pp; | ||
187 | u8 val; | ||
188 | val = *s++; | ||
189 | *pp = s; | ||
190 | return val; | ||
191 | } | ||
192 | |||
193 | static inline u32 _get_word(void **pp) | ||
194 | { | ||
195 | u8 *s = *pp; | ||
196 | u32 val; | ||
197 | val = *s++; | ||
198 | val |= (*s++ << 8); | ||
199 | val |= (*s++ << 16); | ||
200 | val |= (*s++ << 24); | ||
201 | *pp = s; | ||
202 | return val; | ||
203 | } | ||
204 | |||
205 | static inline u32 _get_slice(void **pp, unsigned char *dp) | ||
206 | { | ||
207 | unsigned int len, i; | ||
208 | |||
209 | len = i = _get_word(pp); | ||
210 | while (i-- > 0) *dp++ = _get_byte(pp); | ||
211 | return len; | ||
212 | } | ||
213 | |||
214 | /* ------------------------------------------------------------- */ | ||
215 | |||
216 | void b1dma_reset(avmcard *card) | ||
217 | { | ||
218 | card->csr = 0x0; | ||
219 | b1dma_writel(card, card->csr, AMCC_INTCSR); | ||
220 | b1dma_writel(card, 0, AMCC_MCSR); | ||
221 | b1dma_writel(card, 0, AMCC_RXLEN); | ||
222 | b1dma_writel(card, 0, AMCC_TXLEN); | ||
223 | |||
224 | t1outp(card->port, 0x10, 0x00); | ||
225 | t1outp(card->port, 0x07, 0x00); | ||
226 | |||
227 | b1dma_writel(card, 0, AMCC_MCSR); | ||
228 | mdelay(10); | ||
229 | b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */ | ||
230 | mdelay(10); | ||
231 | b1dma_writel(card, 0, AMCC_MCSR); | ||
232 | if (card->cardtype == avm_t1pci) | ||
233 | mdelay(42); | ||
234 | else | ||
235 | mdelay(10); | ||
236 | } | ||
237 | |||
238 | /* ------------------------------------------------------------- */ | ||
239 | |||
240 | static int b1dma_detect(avmcard *card) | ||
241 | { | ||
242 | b1dma_writel(card, 0, AMCC_MCSR); | ||
243 | mdelay(10); | ||
244 | b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */ | ||
245 | mdelay(10); | ||
246 | b1dma_writel(card, 0, AMCC_MCSR); | ||
247 | mdelay(42); | ||
248 | |||
249 | b1dma_writel(card, 0, AMCC_RXLEN); | ||
250 | b1dma_writel(card, 0, AMCC_TXLEN); | ||
251 | card->csr = 0x0; | ||
252 | b1dma_writel(card, card->csr, AMCC_INTCSR); | ||
253 | |||
254 | if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6) | ||
255 | return 1; | ||
256 | |||
257 | b1dma_writel(card, 0xffffffff, AMCC_RXPTR); | ||
258 | b1dma_writel(card, 0xffffffff, AMCC_TXPTR); | ||
259 | if ( b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc | ||
260 | || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc) | ||
261 | return 2; | ||
262 | |||
263 | b1dma_writel(card, 0x0, AMCC_RXPTR); | ||
264 | b1dma_writel(card, 0x0, AMCC_TXPTR); | ||
265 | if ( b1dma_readl(card, AMCC_RXPTR) != 0x0 | ||
266 | || b1dma_readl(card, AMCC_TXPTR) != 0x0) | ||
267 | return 3; | ||
268 | |||
269 | t1outp(card->port, 0x10, 0x00); | ||
270 | t1outp(card->port, 0x07, 0x00); | ||
271 | |||
272 | t1outp(card->port, 0x02, 0x02); | ||
273 | t1outp(card->port, 0x03, 0x02); | ||
274 | |||
275 | if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02 | ||
276 | || t1inp(card->port, 0x3) != 0x03) | ||
277 | return 4; | ||
278 | |||
279 | t1outp(card->port, 0x02, 0x00); | ||
280 | t1outp(card->port, 0x03, 0x00); | ||
281 | |||
282 | if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00 | ||
283 | || t1inp(card->port, 0x3) != 0x01) | ||
284 | return 5; | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | int t1pci_detect(avmcard *card) | ||
290 | { | ||
291 | int ret; | ||
292 | |||
293 | if ((ret = b1dma_detect(card)) != 0) | ||
294 | return ret; | ||
295 | |||
296 | /* Transputer test */ | ||
297 | |||
298 | if ( WriteReg(card, 0x80001000, 0x11) != 0 | ||
299 | || WriteReg(card, 0x80101000, 0x22) != 0 | ||
300 | || WriteReg(card, 0x80201000, 0x33) != 0 | ||
301 | || WriteReg(card, 0x80301000, 0x44) != 0) | ||
302 | return 6; | ||
303 | |||
304 | if ( ReadReg(card, 0x80001000) != 0x11 | ||
305 | || ReadReg(card, 0x80101000) != 0x22 | ||
306 | || ReadReg(card, 0x80201000) != 0x33 | ||
307 | || ReadReg(card, 0x80301000) != 0x44) | ||
308 | return 7; | ||
309 | |||
310 | if ( WriteReg(card, 0x80001000, 0x55) != 0 | ||
311 | || WriteReg(card, 0x80101000, 0x66) != 0 | ||
312 | || WriteReg(card, 0x80201000, 0x77) != 0 | ||
313 | || WriteReg(card, 0x80301000, 0x88) != 0) | ||
314 | return 8; | ||
315 | |||
316 | if ( ReadReg(card, 0x80001000) != 0x55 | ||
317 | || ReadReg(card, 0x80101000) != 0x66 | ||
318 | || ReadReg(card, 0x80201000) != 0x77 | ||
319 | || ReadReg(card, 0x80301000) != 0x88) | ||
320 | return 9; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | int b1pciv4_detect(avmcard *card) | ||
326 | { | ||
327 | int ret, i; | ||
328 | |||
329 | if ((ret = b1dma_detect(card)) != 0) | ||
330 | return ret; | ||
331 | |||
332 | for (i=0; i < 5 ; i++) { | ||
333 | if (WriteReg(card, 0x80A00000, 0x21) != 0) | ||
334 | return 6; | ||
335 | if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01) | ||
336 | return 7; | ||
337 | } | ||
338 | for (i=0; i < 5 ; i++) { | ||
339 | if (WriteReg(card, 0x80A00000, 0x20) != 0) | ||
340 | return 8; | ||
341 | if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00) | ||
342 | return 9; | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb) | ||
349 | { | ||
350 | unsigned long flags; | ||
351 | |||
352 | spin_lock_irqsave(&card->lock, flags); | ||
353 | |||
354 | skb_queue_tail(&card->dma->send_queue, skb); | ||
355 | |||
356 | if (!(card->csr & EN_TX_TC_INT)) { | ||
357 | b1dma_dispatch_tx(card); | ||
358 | b1dma_writel(card, card->csr, AMCC_INTCSR); | ||
359 | } | ||
360 | |||
361 | spin_unlock_irqrestore(&card->lock, flags); | ||
362 | } | ||
363 | |||
364 | /* ------------------------------------------------------------- */ | ||
365 | |||
366 | static void b1dma_dispatch_tx(avmcard *card) | ||
367 | { | ||
368 | avmcard_dmainfo *dma = card->dma; | ||
369 | struct sk_buff *skb; | ||
370 | u8 cmd, subcmd; | ||
371 | u16 len; | ||
372 | u32 txlen; | ||
373 | void *p; | ||
374 | |||
375 | skb = skb_dequeue(&dma->send_queue); | ||
376 | |||
377 | len = CAPIMSG_LEN(skb->data); | ||
378 | |||
379 | if (len) { | ||
380 | cmd = CAPIMSG_COMMAND(skb->data); | ||
381 | subcmd = CAPIMSG_SUBCOMMAND(skb->data); | ||
382 | |||
383 | p = dma->sendbuf.dmabuf; | ||
384 | |||
385 | if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { | ||
386 | u16 dlen = CAPIMSG_DATALEN(skb->data); | ||
387 | _put_byte(&p, SEND_DATA_B3_REQ); | ||
388 | _put_slice(&p, skb->data, len); | ||
389 | _put_slice(&p, skb->data + len, dlen); | ||
390 | } else { | ||
391 | _put_byte(&p, SEND_MESSAGE); | ||
392 | _put_slice(&p, skb->data, len); | ||
393 | } | ||
394 | txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; | ||
395 | #ifdef CONFIG_B1DMA_DEBUG | ||
396 | printk(KERN_DEBUG "tx: put msg len=%d\n", txlen); | ||
397 | #endif | ||
398 | } else { | ||
399 | txlen = skb->len-2; | ||
400 | #ifdef CONFIG_B1DMA_POLLDEBUG | ||
401 | if (skb->data[2] == SEND_POLLACK) | ||
402 | printk(KERN_INFO "%s: send ack\n", card->name); | ||
403 | #endif | ||
404 | #ifdef CONFIG_B1DMA_DEBUG | ||
405 | printk(KERN_DEBUG "tx: put 0x%x len=%d\n", | ||
406 | skb->data[2], txlen); | ||
407 | #endif | ||
408 | memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2); | ||
409 | } | ||
410 | txlen = (txlen + 3) & ~3; | ||
411 | |||
412 | b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR); | ||
413 | b1dma_writel(card, txlen, AMCC_TXLEN); | ||
414 | |||
415 | card->csr |= EN_TX_TC_INT; | ||
416 | |||
417 | dev_kfree_skb_any(skb); | ||
418 | } | ||
419 | |||
420 | /* ------------------------------------------------------------- */ | ||
421 | |||
422 | static void queue_pollack(avmcard *card) | ||
423 | { | ||
424 | struct sk_buff *skb; | ||
425 | void *p; | ||
426 | |||
427 | skb = alloc_skb(3, GFP_ATOMIC); | ||
428 | if (!skb) { | ||
429 | printk(KERN_CRIT "%s: no memory, lost poll ack\n", | ||
430 | card->name); | ||
431 | return; | ||
432 | } | ||
433 | p = skb->data; | ||
434 | _put_byte(&p, 0); | ||
435 | _put_byte(&p, 0); | ||
436 | _put_byte(&p, SEND_POLLACK); | ||
437 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
438 | |||
439 | b1dma_queue_tx(card, skb); | ||
440 | } | ||
441 | |||
442 | /* ------------------------------------------------------------- */ | ||
443 | |||
444 | static void b1dma_handle_rx(avmcard *card) | ||
445 | { | ||
446 | avmctrl_info *cinfo = &card->ctrlinfo[0]; | ||
447 | avmcard_dmainfo *dma = card->dma; | ||
448 | struct capi_ctr *ctrl = &cinfo->capi_ctrl; | ||
449 | struct sk_buff *skb; | ||
450 | void *p = dma->recvbuf.dmabuf+4; | ||
451 | u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; | ||
452 | u8 b1cmd = _get_byte(&p); | ||
453 | |||
454 | #ifdef CONFIG_B1DMA_DEBUG | ||
455 | printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen); | ||
456 | #endif | ||
457 | |||
458 | switch (b1cmd) { | ||
459 | case RECEIVE_DATA_B3_IND: | ||
460 | |||
461 | ApplId = (unsigned) _get_word(&p); | ||
462 | MsgLen = _get_slice(&p, card->msgbuf); | ||
463 | DataB3Len = _get_slice(&p, card->databuf); | ||
464 | |||
465 | if (MsgLen < 30) { /* not CAPI 64Bit */ | ||
466 | memset(card->msgbuf+MsgLen, 0, 30-MsgLen); | ||
467 | MsgLen = 30; | ||
468 | CAPIMSG_SETLEN(card->msgbuf, 30); | ||
469 | } | ||
470 | if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { | ||
471 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
472 | card->name); | ||
473 | } else { | ||
474 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
475 | memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); | ||
476 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
477 | } | ||
478 | break; | ||
479 | |||
480 | case RECEIVE_MESSAGE: | ||
481 | |||
482 | ApplId = (unsigned) _get_word(&p); | ||
483 | MsgLen = _get_slice(&p, card->msgbuf); | ||
484 | if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { | ||
485 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
486 | card->name); | ||
487 | } else { | ||
488 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
489 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) | ||
490 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | ||
491 | CAPIMSG_NCCI(skb->data), | ||
492 | CAPIMSG_MSGID(skb->data)); | ||
493 | |||
494 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
495 | } | ||
496 | break; | ||
497 | |||
498 | case RECEIVE_NEW_NCCI: | ||
499 | |||
500 | ApplId = _get_word(&p); | ||
501 | NCCI = _get_word(&p); | ||
502 | WindowSize = _get_word(&p); | ||
503 | |||
504 | capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); | ||
505 | |||
506 | break; | ||
507 | |||
508 | case RECEIVE_FREE_NCCI: | ||
509 | |||
510 | ApplId = _get_word(&p); | ||
511 | NCCI = _get_word(&p); | ||
512 | |||
513 | if (NCCI != 0xffffffff) | ||
514 | capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); | ||
515 | |||
516 | break; | ||
517 | |||
518 | case RECEIVE_START: | ||
519 | #ifdef CONFIG_B1DMA_POLLDEBUG | ||
520 | printk(KERN_INFO "%s: receive poll\n", card->name); | ||
521 | #endif | ||
522 | if (!suppress_pollack) | ||
523 | queue_pollack(card); | ||
524 | capi_ctr_resume_output(ctrl); | ||
525 | break; | ||
526 | |||
527 | case RECEIVE_STOP: | ||
528 | capi_ctr_suspend_output(ctrl); | ||
529 | break; | ||
530 | |||
531 | case RECEIVE_INIT: | ||
532 | |||
533 | cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); | ||
534 | b1_parse_version(cinfo); | ||
535 | printk(KERN_INFO "%s: %s-card (%s) now active\n", | ||
536 | card->name, | ||
537 | cinfo->version[VER_CARDTYPE], | ||
538 | cinfo->version[VER_DRIVER]); | ||
539 | capi_ctr_ready(ctrl); | ||
540 | break; | ||
541 | |||
542 | case RECEIVE_TASK_READY: | ||
543 | ApplId = (unsigned) _get_word(&p); | ||
544 | MsgLen = _get_slice(&p, card->msgbuf); | ||
545 | card->msgbuf[MsgLen] = 0; | ||
546 | while ( MsgLen > 0 | ||
547 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
548 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
549 | card->msgbuf[MsgLen-1] = 0; | ||
550 | MsgLen--; | ||
551 | } | ||
552 | printk(KERN_INFO "%s: task %d \"%s\" ready.\n", | ||
553 | card->name, ApplId, card->msgbuf); | ||
554 | break; | ||
555 | |||
556 | case RECEIVE_DEBUGMSG: | ||
557 | MsgLen = _get_slice(&p, card->msgbuf); | ||
558 | card->msgbuf[MsgLen] = 0; | ||
559 | while ( MsgLen > 0 | ||
560 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
561 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
562 | card->msgbuf[MsgLen-1] = 0; | ||
563 | MsgLen--; | ||
564 | } | ||
565 | printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); | ||
566 | break; | ||
567 | |||
568 | default: | ||
569 | printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n", | ||
570 | card->name, b1cmd); | ||
571 | return; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | /* ------------------------------------------------------------- */ | ||
576 | |||
577 | static void b1dma_handle_interrupt(avmcard *card) | ||
578 | { | ||
579 | u32 status; | ||
580 | u32 newcsr; | ||
581 | |||
582 | spin_lock(&card->lock); | ||
583 | |||
584 | status = b1dma_readl(card, AMCC_INTCSR); | ||
585 | if ((status & ANY_S5933_INT) == 0) { | ||
586 | spin_unlock(&card->lock); | ||
587 | return; | ||
588 | } | ||
589 | |||
590 | newcsr = card->csr | (status & ALL_INT); | ||
591 | if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; | ||
592 | if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; | ||
593 | b1dma_writel(card, newcsr, AMCC_INTCSR); | ||
594 | |||
595 | if ((status & RX_TC_INT) != 0) { | ||
596 | struct avmcard_dmainfo *dma = card->dma; | ||
597 | u32 rxlen; | ||
598 | if (card->dma->recvlen == 0) { | ||
599 | rxlen = b1dma_readl(card, AMCC_RXLEN); | ||
600 | if (rxlen == 0) { | ||
601 | dma->recvlen = *((u32 *)dma->recvbuf.dmabuf); | ||
602 | rxlen = (dma->recvlen + 3) & ~3; | ||
603 | b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR); | ||
604 | b1dma_writel(card, rxlen, AMCC_RXLEN); | ||
605 | #ifdef CONFIG_B1DMA_DEBUG | ||
606 | } else { | ||
607 | printk(KERN_ERR "%s: rx not complete (%d).\n", | ||
608 | card->name, rxlen); | ||
609 | #endif | ||
610 | } | ||
611 | } else { | ||
612 | spin_unlock(&card->lock); | ||
613 | b1dma_handle_rx(card); | ||
614 | dma->recvlen = 0; | ||
615 | spin_lock(&card->lock); | ||
616 | b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR); | ||
617 | b1dma_writel(card, 4, AMCC_RXLEN); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | if ((status & TX_TC_INT) != 0) { | ||
622 | if (skb_queue_empty(&card->dma->send_queue)) | ||
623 | card->csr &= ~EN_TX_TC_INT; | ||
624 | else | ||
625 | b1dma_dispatch_tx(card); | ||
626 | } | ||
627 | b1dma_writel(card, card->csr, AMCC_INTCSR); | ||
628 | |||
629 | spin_unlock(&card->lock); | ||
630 | } | ||
631 | |||
632 | irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs) | ||
633 | { | ||
634 | avmcard *card = devptr; | ||
635 | |||
636 | b1dma_handle_interrupt(card); | ||
637 | return IRQ_HANDLED; | ||
638 | } | ||
639 | |||
640 | /* ------------------------------------------------------------- */ | ||
641 | |||
642 | static int b1dma_loaded(avmcard *card) | ||
643 | { | ||
644 | unsigned long stop; | ||
645 | unsigned char ans; | ||
646 | unsigned long tout = 2; | ||
647 | unsigned int base = card->port; | ||
648 | |||
649 | for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { | ||
650 | if (b1_tx_empty(base)) | ||
651 | break; | ||
652 | } | ||
653 | if (!b1_tx_empty(base)) { | ||
654 | printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n", | ||
655 | card->name); | ||
656 | return 0; | ||
657 | } | ||
658 | b1_put_byte(base, SEND_POLLACK); | ||
659 | for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { | ||
660 | if (b1_rx_full(base)) { | ||
661 | if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { | ||
662 | return 1; | ||
663 | } | ||
664 | printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); | ||
665 | return 0; | ||
666 | } | ||
667 | } | ||
668 | printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | /* ------------------------------------------------------------- */ | ||
673 | |||
674 | static void b1dma_send_init(avmcard *card) | ||
675 | { | ||
676 | struct sk_buff *skb; | ||
677 | void *p; | ||
678 | |||
679 | skb = alloc_skb(15, GFP_ATOMIC); | ||
680 | if (!skb) { | ||
681 | printk(KERN_CRIT "%s: no memory, lost register appl.\n", | ||
682 | card->name); | ||
683 | return; | ||
684 | } | ||
685 | p = skb->data; | ||
686 | _put_byte(&p, 0); | ||
687 | _put_byte(&p, 0); | ||
688 | _put_byte(&p, SEND_INIT); | ||
689 | _put_word(&p, CAPI_MAXAPPL); | ||
690 | _put_word(&p, AVM_NCCI_PER_CHANNEL*30); | ||
691 | _put_word(&p, card->cardnr - 1); | ||
692 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
693 | |||
694 | b1dma_queue_tx(card, skb); | ||
695 | } | ||
696 | |||
697 | int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) | ||
698 | { | ||
699 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
700 | avmcard *card = cinfo->card; | ||
701 | int retval; | ||
702 | |||
703 | b1dma_reset(card); | ||
704 | |||
705 | if ((retval = b1_load_t4file(card, &data->firmware))) { | ||
706 | b1dma_reset(card); | ||
707 | printk(KERN_ERR "%s: failed to load t4file!!\n", | ||
708 | card->name); | ||
709 | return retval; | ||
710 | } | ||
711 | |||
712 | if (data->configuration.len > 0 && data->configuration.data) { | ||
713 | if ((retval = b1_load_config(card, &data->configuration))) { | ||
714 | b1dma_reset(card); | ||
715 | printk(KERN_ERR "%s: failed to load config!!\n", | ||
716 | card->name); | ||
717 | return retval; | ||
718 | } | ||
719 | } | ||
720 | |||
721 | if (!b1dma_loaded(card)) { | ||
722 | b1dma_reset(card); | ||
723 | printk(KERN_ERR "%s: failed to load t4file.\n", card->name); | ||
724 | return -EIO; | ||
725 | } | ||
726 | |||
727 | card->csr = AVM_FLAG; | ||
728 | b1dma_writel(card, card->csr, AMCC_INTCSR); | ||
729 | b1dma_writel(card, EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|A2P_HI_PRIORITY| | ||
730 | P2A_HI_PRIORITY|RESET_A2P_FLAGS|RESET_P2A_FLAGS, | ||
731 | AMCC_MCSR); | ||
732 | t1outp(card->port, 0x07, 0x30); | ||
733 | t1outp(card->port, 0x10, 0xF0); | ||
734 | |||
735 | card->dma->recvlen = 0; | ||
736 | b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR); | ||
737 | b1dma_writel(card, 4, AMCC_RXLEN); | ||
738 | card->csr |= EN_RX_TC_INT; | ||
739 | b1dma_writel(card, card->csr, AMCC_INTCSR); | ||
740 | |||
741 | b1dma_send_init(card); | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | void b1dma_reset_ctr(struct capi_ctr *ctrl) | ||
747 | { | ||
748 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
749 | avmcard *card = cinfo->card; | ||
750 | unsigned long flags; | ||
751 | |||
752 | spin_lock_irqsave(&card->lock, flags); | ||
753 | b1dma_reset(card); | ||
754 | spin_unlock_irqrestore(&card->lock, flags); | ||
755 | |||
756 | memset(cinfo->version, 0, sizeof(cinfo->version)); | ||
757 | capilib_release(&cinfo->ncci_head); | ||
758 | capi_ctr_reseted(ctrl); | ||
759 | } | ||
760 | |||
761 | /* ------------------------------------------------------------- */ | ||
762 | |||
763 | void b1dma_register_appl(struct capi_ctr *ctrl, | ||
764 | u16 appl, | ||
765 | capi_register_params *rp) | ||
766 | { | ||
767 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
768 | avmcard *card = cinfo->card; | ||
769 | struct sk_buff *skb; | ||
770 | int want = rp->level3cnt; | ||
771 | int nconn; | ||
772 | void *p; | ||
773 | |||
774 | if (want > 0) nconn = want; | ||
775 | else nconn = ctrl->profile.nbchannel * -want; | ||
776 | if (nconn == 0) nconn = ctrl->profile.nbchannel; | ||
777 | |||
778 | skb = alloc_skb(23, GFP_ATOMIC); | ||
779 | if (!skb) { | ||
780 | printk(KERN_CRIT "%s: no memory, lost register appl.\n", | ||
781 | card->name); | ||
782 | return; | ||
783 | } | ||
784 | p = skb->data; | ||
785 | _put_byte(&p, 0); | ||
786 | _put_byte(&p, 0); | ||
787 | _put_byte(&p, SEND_REGISTER); | ||
788 | _put_word(&p, appl); | ||
789 | _put_word(&p, 1024 * (nconn+1)); | ||
790 | _put_word(&p, nconn); | ||
791 | _put_word(&p, rp->datablkcnt); | ||
792 | _put_word(&p, rp->datablklen); | ||
793 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
794 | |||
795 | b1dma_queue_tx(card, skb); | ||
796 | } | ||
797 | |||
798 | /* ------------------------------------------------------------- */ | ||
799 | |||
800 | void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl) | ||
801 | { | ||
802 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
803 | avmcard *card = cinfo->card; | ||
804 | struct sk_buff *skb; | ||
805 | void *p; | ||
806 | |||
807 | capilib_release_appl(&cinfo->ncci_head, appl); | ||
808 | |||
809 | skb = alloc_skb(7, GFP_ATOMIC); | ||
810 | if (!skb) { | ||
811 | printk(KERN_CRIT "%s: no memory, lost release appl.\n", | ||
812 | card->name); | ||
813 | return; | ||
814 | } | ||
815 | p = skb->data; | ||
816 | _put_byte(&p, 0); | ||
817 | _put_byte(&p, 0); | ||
818 | _put_byte(&p, SEND_RELEASE); | ||
819 | _put_word(&p, appl); | ||
820 | |||
821 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
822 | |||
823 | b1dma_queue_tx(card, skb); | ||
824 | } | ||
825 | |||
826 | /* ------------------------------------------------------------- */ | ||
827 | |||
828 | u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | ||
829 | { | ||
830 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
831 | avmcard *card = cinfo->card; | ||
832 | u16 retval = CAPI_NOERROR; | ||
833 | |||
834 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { | ||
835 | retval = capilib_data_b3_req(&cinfo->ncci_head, | ||
836 | CAPIMSG_APPID(skb->data), | ||
837 | CAPIMSG_NCCI(skb->data), | ||
838 | CAPIMSG_MSGID(skb->data)); | ||
839 | } | ||
840 | if (retval == CAPI_NOERROR) | ||
841 | b1dma_queue_tx(card, skb); | ||
842 | |||
843 | return retval; | ||
844 | } | ||
845 | |||
846 | /* ------------------------------------------------------------- */ | ||
847 | |||
848 | int b1dmactl_read_proc(char *page, char **start, off_t off, | ||
849 | int count, int *eof, struct capi_ctr *ctrl) | ||
850 | { | ||
851 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
852 | avmcard *card = cinfo->card; | ||
853 | u8 flag; | ||
854 | int len = 0; | ||
855 | char *s; | ||
856 | u32 txoff, txlen, rxoff, rxlen, csr; | ||
857 | unsigned long flags; | ||
858 | |||
859 | len += sprintf(page+len, "%-16s %s\n", "name", card->name); | ||
860 | len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); | ||
861 | len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); | ||
862 | len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); | ||
863 | switch (card->cardtype) { | ||
864 | case avm_b1isa: s = "B1 ISA"; break; | ||
865 | case avm_b1pci: s = "B1 PCI"; break; | ||
866 | case avm_b1pcmcia: s = "B1 PCMCIA"; break; | ||
867 | case avm_m1: s = "M1"; break; | ||
868 | case avm_m2: s = "M2"; break; | ||
869 | case avm_t1isa: s = "T1 ISA (HEMA)"; break; | ||
870 | case avm_t1pci: s = "T1 PCI"; break; | ||
871 | case avm_c4: s = "C4"; break; | ||
872 | case avm_c2: s = "C2"; break; | ||
873 | default: s = "???"; break; | ||
874 | } | ||
875 | len += sprintf(page+len, "%-16s %s\n", "type", s); | ||
876 | if ((s = cinfo->version[VER_DRIVER]) != 0) | ||
877 | len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); | ||
878 | if ((s = cinfo->version[VER_CARDTYPE]) != 0) | ||
879 | len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); | ||
880 | if ((s = cinfo->version[VER_SERIAL]) != 0) | ||
881 | len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); | ||
882 | |||
883 | if (card->cardtype != avm_m1) { | ||
884 | flag = ((u8 *)(ctrl->profile.manu))[3]; | ||
885 | if (flag) | ||
886 | len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", | ||
887 | "protocol", | ||
888 | (flag & 0x01) ? " DSS1" : "", | ||
889 | (flag & 0x02) ? " CT1" : "", | ||
890 | (flag & 0x04) ? " VN3" : "", | ||
891 | (flag & 0x08) ? " NI1" : "", | ||
892 | (flag & 0x10) ? " AUSTEL" : "", | ||
893 | (flag & 0x20) ? " ESS" : "", | ||
894 | (flag & 0x40) ? " 1TR6" : "" | ||
895 | ); | ||
896 | } | ||
897 | if (card->cardtype != avm_m1) { | ||
898 | flag = ((u8 *)(ctrl->profile.manu))[5]; | ||
899 | if (flag) | ||
900 | len += sprintf(page+len, "%-16s%s%s%s%s\n", | ||
901 | "linetype", | ||
902 | (flag & 0x01) ? " point to point" : "", | ||
903 | (flag & 0x02) ? " point to multipoint" : "", | ||
904 | (flag & 0x08) ? " leased line without D-channel" : "", | ||
905 | (flag & 0x04) ? " leased line with D-channel" : "" | ||
906 | ); | ||
907 | } | ||
908 | len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); | ||
909 | |||
910 | |||
911 | spin_lock_irqsave(&card->lock, flags); | ||
912 | |||
913 | txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr; | ||
914 | txlen = b1dma_readl(card, AMCC_TXLEN); | ||
915 | |||
916 | rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr; | ||
917 | rxlen = b1dma_readl(card, AMCC_RXLEN); | ||
918 | |||
919 | csr = b1dma_readl(card, AMCC_INTCSR); | ||
920 | |||
921 | spin_unlock_irqrestore(&card->lock, flags); | ||
922 | |||
923 | len += sprintf(page+len, "%-16s 0x%lx\n", | ||
924 | "csr (cached)", (unsigned long)card->csr); | ||
925 | len += sprintf(page+len, "%-16s 0x%lx\n", | ||
926 | "csr", (unsigned long)csr); | ||
927 | len += sprintf(page+len, "%-16s %lu\n", | ||
928 | "txoff", (unsigned long)txoff); | ||
929 | len += sprintf(page+len, "%-16s %lu\n", | ||
930 | "txlen", (unsigned long)txlen); | ||
931 | len += sprintf(page+len, "%-16s %lu\n", | ||
932 | "rxoff", (unsigned long)rxoff); | ||
933 | len += sprintf(page+len, "%-16s %lu\n", | ||
934 | "rxlen", (unsigned long)rxlen); | ||
935 | |||
936 | if (off+count >= len) | ||
937 | *eof = 1; | ||
938 | if (len < off) | ||
939 | return 0; | ||
940 | *start = page + off; | ||
941 | return ((count < len-off) ? count : len-off); | ||
942 | } | ||
943 | |||
944 | /* ------------------------------------------------------------- */ | ||
945 | |||
946 | EXPORT_SYMBOL(b1dma_reset); | ||
947 | EXPORT_SYMBOL(t1pci_detect); | ||
948 | EXPORT_SYMBOL(b1pciv4_detect); | ||
949 | EXPORT_SYMBOL(b1dma_interrupt); | ||
950 | |||
951 | EXPORT_SYMBOL(b1dma_load_firmware); | ||
952 | EXPORT_SYMBOL(b1dma_reset_ctr); | ||
953 | EXPORT_SYMBOL(b1dma_register_appl); | ||
954 | EXPORT_SYMBOL(b1dma_release_appl); | ||
955 | EXPORT_SYMBOL(b1dma_send_message); | ||
956 | EXPORT_SYMBOL(b1dmactl_read_proc); | ||
957 | |||
958 | int b1dma_init(void) | ||
959 | { | ||
960 | char *p; | ||
961 | char rev[32]; | ||
962 | |||
963 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
964 | strlcpy(rev, p + 2, sizeof(rev)); | ||
965 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
966 | *(p-1) = 0; | ||
967 | } else | ||
968 | strcpy(rev, "1.0"); | ||
969 | |||
970 | printk(KERN_INFO "b1dma: revision %s\n", rev); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | void b1dma_exit(void) | ||
976 | { | ||
977 | } | ||
978 | |||
979 | module_init(b1dma_init); | ||
980 | module_exit(b1dma_exit); | ||
diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c new file mode 100644 index 000000000000..38bd4dfecbd1 --- /dev/null +++ b/drivers/isdn/hardware/avm/b1isa.c | |||
@@ -0,0 +1,245 @@ | |||
1 | /* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM B1 ISA-card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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 | #include <linux/kernel.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/capi.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <linux/isdn/capicmd.h> | ||
24 | #include <linux/isdn/capiutil.h> | ||
25 | #include <linux/isdn/capilli.h> | ||
26 | #include "avmcard.h" | ||
27 | |||
28 | /* ------------------------------------------------------------- */ | ||
29 | |||
30 | static char *revision = "$Revision: 1.1.2.3 $"; | ||
31 | |||
32 | /* ------------------------------------------------------------- */ | ||
33 | |||
34 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card"); | ||
35 | MODULE_AUTHOR("Carsten Paeth"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | /* ------------------------------------------------------------- */ | ||
39 | |||
40 | static void b1isa_remove(struct pci_dev *pdev) | ||
41 | { | ||
42 | avmctrl_info *cinfo = pci_get_drvdata(pdev); | ||
43 | avmcard *card; | ||
44 | |||
45 | if (!cinfo) | ||
46 | return; | ||
47 | |||
48 | card = cinfo->card; | ||
49 | |||
50 | b1_reset(card->port); | ||
51 | b1_reset(card->port); | ||
52 | |||
53 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
54 | free_irq(card->irq, card); | ||
55 | release_region(card->port, AVMB1_PORTLEN); | ||
56 | b1_free_card(card); | ||
57 | } | ||
58 | |||
59 | /* ------------------------------------------------------------- */ | ||
60 | |||
61 | static char *b1isa_procinfo(struct capi_ctr *ctrl); | ||
62 | |||
63 | static int b1isa_probe(struct pci_dev *pdev) | ||
64 | { | ||
65 | avmctrl_info *cinfo; | ||
66 | avmcard *card; | ||
67 | int retval; | ||
68 | |||
69 | card = b1_alloc_card(1); | ||
70 | if (!card) { | ||
71 | printk(KERN_WARNING "b1isa: no memory.\n"); | ||
72 | retval = -ENOMEM; | ||
73 | goto err; | ||
74 | } | ||
75 | |||
76 | cinfo = card->ctrlinfo; | ||
77 | |||
78 | card->port = pci_resource_start(pdev, 0); | ||
79 | card->irq = pdev->irq; | ||
80 | card->cardtype = avm_b1isa; | ||
81 | sprintf(card->name, "b1isa-%x", card->port); | ||
82 | |||
83 | if ( card->port != 0x150 && card->port != 0x250 | ||
84 | && card->port != 0x300 && card->port != 0x340) { | ||
85 | printk(KERN_WARNING "b1isa: invalid port 0x%x.\n", card->port); | ||
86 | retval = -EINVAL; | ||
87 | goto err_free; | ||
88 | } | ||
89 | if (b1_irq_table[card->irq & 0xf] == 0) { | ||
90 | printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); | ||
91 | retval = -EINVAL; | ||
92 | goto err_free; | ||
93 | } | ||
94 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
95 | printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n", | ||
96 | card->port, card->port + AVMB1_PORTLEN); | ||
97 | retval = -EBUSY; | ||
98 | goto err_free; | ||
99 | } | ||
100 | retval = request_irq(card->irq, b1_interrupt, 0, card->name, card); | ||
101 | if (retval) { | ||
102 | printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq); | ||
103 | goto err_release_region; | ||
104 | } | ||
105 | b1_reset(card->port); | ||
106 | if ((retval = b1_detect(card->port, card->cardtype)) != 0) { | ||
107 | printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n", | ||
108 | card->port, retval); | ||
109 | retval = -ENODEV; | ||
110 | goto err_free_irq; | ||
111 | } | ||
112 | b1_reset(card->port); | ||
113 | b1_getrevision(card); | ||
114 | |||
115 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
116 | cinfo->capi_ctrl.driver_name = "b1isa"; | ||
117 | cinfo->capi_ctrl.driverdata = cinfo; | ||
118 | cinfo->capi_ctrl.register_appl = b1_register_appl; | ||
119 | cinfo->capi_ctrl.release_appl = b1_release_appl; | ||
120 | cinfo->capi_ctrl.send_message = b1_send_message; | ||
121 | cinfo->capi_ctrl.load_firmware = b1_load_firmware; | ||
122 | cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; | ||
123 | cinfo->capi_ctrl.procinfo = b1isa_procinfo; | ||
124 | cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; | ||
125 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
126 | |||
127 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
128 | if (retval) { | ||
129 | printk(KERN_ERR "b1isa: attach controller failed.\n"); | ||
130 | goto err_free_irq; | ||
131 | } | ||
132 | |||
133 | printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n", | ||
134 | card->port, card->irq, card->revision); | ||
135 | |||
136 | pci_set_drvdata(pdev, cinfo); | ||
137 | return 0; | ||
138 | |||
139 | err_free_irq: | ||
140 | free_irq(card->irq, card); | ||
141 | err_release_region: | ||
142 | release_region(card->port, AVMB1_PORTLEN); | ||
143 | err_free: | ||
144 | b1_free_card(card); | ||
145 | err: | ||
146 | return retval; | ||
147 | } | ||
148 | |||
149 | static char *b1isa_procinfo(struct capi_ctr *ctrl) | ||
150 | { | ||
151 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
152 | |||
153 | if (!cinfo) | ||
154 | return ""; | ||
155 | sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", | ||
156 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
157 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
158 | cinfo->card ? cinfo->card->port : 0x0, | ||
159 | cinfo->card ? cinfo->card->irq : 0, | ||
160 | cinfo->card ? cinfo->card->revision : 0 | ||
161 | ); | ||
162 | return cinfo->infobuf; | ||
163 | } | ||
164 | |||
165 | /* ------------------------------------------------------------- */ | ||
166 | |||
167 | #define MAX_CARDS 4 | ||
168 | static struct pci_dev isa_dev[MAX_CARDS]; | ||
169 | static int io[MAX_CARDS]; | ||
170 | static int irq[MAX_CARDS]; | ||
171 | |||
172 | MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); | ||
173 | MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i"); | ||
174 | MODULE_PARM_DESC(io, "I/O base address(es)"); | ||
175 | MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); | ||
176 | |||
177 | static int b1isa_add_card(struct capi_driver *driver, capicardparams *data) | ||
178 | { | ||
179 | int i; | ||
180 | |||
181 | for (i = 0; i < MAX_CARDS; i++) { | ||
182 | if (isa_dev[i].resource[0].start) | ||
183 | continue; | ||
184 | |||
185 | isa_dev[i].resource[0].start = data->port; | ||
186 | isa_dev[i].irq = data->irq; | ||
187 | |||
188 | if (b1isa_probe(&isa_dev[i]) == 0) | ||
189 | return 0; | ||
190 | } | ||
191 | return -ENODEV; | ||
192 | } | ||
193 | |||
194 | static struct capi_driver capi_driver_b1isa = { | ||
195 | .name = "b1isa", | ||
196 | .revision = "1.0", | ||
197 | .add_card = b1isa_add_card, | ||
198 | }; | ||
199 | |||
200 | static int __init b1isa_init(void) | ||
201 | { | ||
202 | char *p; | ||
203 | char rev[32]; | ||
204 | int i; | ||
205 | |||
206 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
207 | strlcpy(rev, p + 2, 32); | ||
208 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
209 | *(p-1) = 0; | ||
210 | } else | ||
211 | strcpy(rev, "1.0"); | ||
212 | |||
213 | for (i = 0; i < MAX_CARDS; i++) { | ||
214 | if (!io[i]) | ||
215 | break; | ||
216 | |||
217 | isa_dev[i].resource[0].start = io[i]; | ||
218 | isa_dev[i].irq = irq[i]; | ||
219 | |||
220 | if (b1isa_probe(&isa_dev[i]) != 0) | ||
221 | return -ENODEV; | ||
222 | } | ||
223 | |||
224 | strlcpy(capi_driver_b1isa.revision, rev, 32); | ||
225 | register_capi_driver(&capi_driver_b1isa); | ||
226 | printk(KERN_INFO "b1isa: revision %s\n", rev); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void __exit b1isa_exit(void) | ||
232 | { | ||
233 | int i; | ||
234 | |||
235 | for (i = 0; i < MAX_CARDS; i++) { | ||
236 | if (!io[i]) | ||
237 | break; | ||
238 | |||
239 | b1isa_remove(&isa_dev[i]); | ||
240 | } | ||
241 | unregister_capi_driver(&capi_driver_b1isa); | ||
242 | } | ||
243 | |||
244 | module_init(b1isa_init); | ||
245 | module_exit(b1isa_exit); | ||
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c new file mode 100644 index 000000000000..5435a6cfb5e7 --- /dev/null +++ b/drivers/isdn/hardware/avm/b1pci.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM B1 PCI-card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/capi.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/isdn/capicmd.h> | ||
25 | #include <linux/isdn/capiutil.h> | ||
26 | #include <linux/isdn/capilli.h> | ||
27 | #include "avmcard.h" | ||
28 | |||
29 | /* ------------------------------------------------------------- */ | ||
30 | |||
31 | static char *revision = "$Revision: 1.1.2.2 $"; | ||
32 | |||
33 | /* ------------------------------------------------------------- */ | ||
34 | |||
35 | static struct pci_device_id b1pci_pci_tbl[] = { | ||
36 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID }, | ||
37 | { } /* Terminating entry */ | ||
38 | }; | ||
39 | |||
40 | MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl); | ||
41 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card"); | ||
42 | MODULE_AUTHOR("Carsten Paeth"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | /* ------------------------------------------------------------- */ | ||
46 | |||
47 | static char *b1pci_procinfo(struct capi_ctr *ctrl) | ||
48 | { | ||
49 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
50 | |||
51 | if (!cinfo) | ||
52 | return ""; | ||
53 | sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", | ||
54 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
55 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
56 | cinfo->card ? cinfo->card->port : 0x0, | ||
57 | cinfo->card ? cinfo->card->irq : 0, | ||
58 | cinfo->card ? cinfo->card->revision : 0 | ||
59 | ); | ||
60 | return cinfo->infobuf; | ||
61 | } | ||
62 | |||
63 | /* ------------------------------------------------------------- */ | ||
64 | |||
65 | static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev) | ||
66 | { | ||
67 | avmcard *card; | ||
68 | avmctrl_info *cinfo; | ||
69 | int retval; | ||
70 | |||
71 | card = b1_alloc_card(1); | ||
72 | if (!card) { | ||
73 | printk(KERN_WARNING "b1pci: no memory.\n"); | ||
74 | retval = -ENOMEM; | ||
75 | goto err; | ||
76 | } | ||
77 | |||
78 | cinfo = card->ctrlinfo; | ||
79 | sprintf(card->name, "b1pci-%x", p->port); | ||
80 | card->port = p->port; | ||
81 | card->irq = p->irq; | ||
82 | card->cardtype = avm_b1pci; | ||
83 | |||
84 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
85 | printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n", | ||
86 | card->port, card->port + AVMB1_PORTLEN); | ||
87 | retval = -EBUSY; | ||
88 | goto err_free; | ||
89 | } | ||
90 | b1_reset(card->port); | ||
91 | retval = b1_detect(card->port, card->cardtype); | ||
92 | if (retval) { | ||
93 | printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", | ||
94 | card->port, retval); | ||
95 | retval = -ENODEV; | ||
96 | goto err_release_region; | ||
97 | } | ||
98 | b1_reset(card->port); | ||
99 | b1_getrevision(card); | ||
100 | |||
101 | retval = request_irq(card->irq, b1_interrupt, SA_SHIRQ, card->name, card); | ||
102 | if (retval) { | ||
103 | printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq); | ||
104 | retval = -EBUSY; | ||
105 | goto err_release_region; | ||
106 | } | ||
107 | |||
108 | cinfo->capi_ctrl.driver_name = "b1pci"; | ||
109 | cinfo->capi_ctrl.driverdata = cinfo; | ||
110 | cinfo->capi_ctrl.register_appl = b1_register_appl; | ||
111 | cinfo->capi_ctrl.release_appl = b1_release_appl; | ||
112 | cinfo->capi_ctrl.send_message = b1_send_message; | ||
113 | cinfo->capi_ctrl.load_firmware = b1_load_firmware; | ||
114 | cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; | ||
115 | cinfo->capi_ctrl.procinfo = b1pci_procinfo; | ||
116 | cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; | ||
117 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
118 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
119 | |||
120 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
121 | if (retval) { | ||
122 | printk(KERN_ERR "b1pci: attach controller failed.\n"); | ||
123 | goto err_free_irq; | ||
124 | } | ||
125 | |||
126 | if (card->revision >= 4) { | ||
127 | printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n", | ||
128 | card->port, card->irq, card->revision); | ||
129 | } else { | ||
130 | printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n", | ||
131 | card->port, card->irq, card->revision); | ||
132 | } | ||
133 | |||
134 | pci_set_drvdata(pdev, card); | ||
135 | return 0; | ||
136 | |||
137 | err_free_irq: | ||
138 | free_irq(card->irq, card); | ||
139 | err_release_region: | ||
140 | release_region(card->port, AVMB1_PORTLEN); | ||
141 | err_free: | ||
142 | b1_free_card(card); | ||
143 | err: | ||
144 | return retval; | ||
145 | } | ||
146 | |||
147 | static void b1pci_remove(struct pci_dev *pdev) | ||
148 | { | ||
149 | avmcard *card = pci_get_drvdata(pdev); | ||
150 | avmctrl_info *cinfo = card->ctrlinfo; | ||
151 | unsigned int port = card->port; | ||
152 | |||
153 | b1_reset(port); | ||
154 | b1_reset(port); | ||
155 | |||
156 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
157 | free_irq(card->irq, card); | ||
158 | release_region(card->port, AVMB1_PORTLEN); | ||
159 | b1_free_card(card); | ||
160 | } | ||
161 | |||
162 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
163 | /* ------------------------------------------------------------- */ | ||
164 | |||
165 | static char *b1pciv4_procinfo(struct capi_ctr *ctrl) | ||
166 | { | ||
167 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
168 | |||
169 | if (!cinfo) | ||
170 | return ""; | ||
171 | sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d", | ||
172 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
173 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
174 | cinfo->card ? cinfo->card->port : 0x0, | ||
175 | cinfo->card ? cinfo->card->irq : 0, | ||
176 | cinfo->card ? cinfo->card->membase : 0, | ||
177 | cinfo->card ? cinfo->card->revision : 0 | ||
178 | ); | ||
179 | return cinfo->infobuf; | ||
180 | } | ||
181 | |||
182 | /* ------------------------------------------------------------- */ | ||
183 | |||
184 | static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) | ||
185 | { | ||
186 | avmcard *card; | ||
187 | avmctrl_info *cinfo; | ||
188 | int retval; | ||
189 | |||
190 | card = b1_alloc_card(1); | ||
191 | if (!card) { | ||
192 | printk(KERN_WARNING "b1pci: no memory.\n"); | ||
193 | retval = -ENOMEM; | ||
194 | goto err; | ||
195 | } | ||
196 | |||
197 | card->dma = avmcard_dma_alloc("b1pci", pdev, 2048+128, 2048+128); | ||
198 | if (!card->dma) { | ||
199 | printk(KERN_WARNING "b1pci: dma alloc.\n"); | ||
200 | retval = -ENOMEM; | ||
201 | goto err_free; | ||
202 | } | ||
203 | |||
204 | cinfo = card->ctrlinfo; | ||
205 | sprintf(card->name, "b1pciv4-%x", p->port); | ||
206 | card->port = p->port; | ||
207 | card->irq = p->irq; | ||
208 | card->membase = p->membase; | ||
209 | card->cardtype = avm_b1pci; | ||
210 | |||
211 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
212 | printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n", | ||
213 | card->port, card->port + AVMB1_PORTLEN); | ||
214 | retval = -EBUSY; | ||
215 | goto err_free_dma; | ||
216 | } | ||
217 | |||
218 | card->mbase = ioremap(card->membase, 64); | ||
219 | if (!card->mbase) { | ||
220 | printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n", | ||
221 | card->membase); | ||
222 | retval = -ENOMEM; | ||
223 | goto err_release_region; | ||
224 | } | ||
225 | |||
226 | b1dma_reset(card); | ||
227 | |||
228 | retval = b1pciv4_detect(card); | ||
229 | if (retval) { | ||
230 | printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", | ||
231 | card->port, retval); | ||
232 | retval = -ENODEV; | ||
233 | goto err_unmap; | ||
234 | } | ||
235 | b1dma_reset(card); | ||
236 | b1_getrevision(card); | ||
237 | |||
238 | retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); | ||
239 | if (retval) { | ||
240 | printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", | ||
241 | card->irq); | ||
242 | retval = -EBUSY; | ||
243 | goto err_unmap; | ||
244 | } | ||
245 | |||
246 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
247 | cinfo->capi_ctrl.driver_name = "b1pciv4"; | ||
248 | cinfo->capi_ctrl.driverdata = cinfo; | ||
249 | cinfo->capi_ctrl.register_appl = b1dma_register_appl; | ||
250 | cinfo->capi_ctrl.release_appl = b1dma_release_appl; | ||
251 | cinfo->capi_ctrl.send_message = b1dma_send_message; | ||
252 | cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; | ||
253 | cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; | ||
254 | cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; | ||
255 | cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; | ||
256 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
257 | |||
258 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
259 | if (retval) { | ||
260 | printk(KERN_ERR "b1pci: attach controller failed.\n"); | ||
261 | goto err_free_irq; | ||
262 | } | ||
263 | card->cardnr = cinfo->capi_ctrl.cnr; | ||
264 | |||
265 | printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n", | ||
266 | card->port, card->irq, card->membase, card->revision); | ||
267 | |||
268 | pci_set_drvdata(pdev, card); | ||
269 | return 0; | ||
270 | |||
271 | err_free_irq: | ||
272 | free_irq(card->irq, card); | ||
273 | err_unmap: | ||
274 | iounmap(card->mbase); | ||
275 | err_release_region: | ||
276 | release_region(card->port, AVMB1_PORTLEN); | ||
277 | err_free_dma: | ||
278 | avmcard_dma_free(card->dma); | ||
279 | err_free: | ||
280 | b1_free_card(card); | ||
281 | err: | ||
282 | return retval; | ||
283 | |||
284 | } | ||
285 | |||
286 | static void b1pciv4_remove(struct pci_dev *pdev) | ||
287 | { | ||
288 | avmcard *card = pci_get_drvdata(pdev); | ||
289 | avmctrl_info *cinfo = card->ctrlinfo; | ||
290 | |||
291 | b1dma_reset(card); | ||
292 | |||
293 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
294 | free_irq(card->irq, card); | ||
295 | iounmap(card->mbase); | ||
296 | release_region(card->port, AVMB1_PORTLEN); | ||
297 | avmcard_dma_free(card->dma); | ||
298 | b1_free_card(card); | ||
299 | } | ||
300 | |||
301 | #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ | ||
302 | |||
303 | static int __devinit b1pci_pci_probe(struct pci_dev *pdev, | ||
304 | const struct pci_device_id *ent) | ||
305 | { | ||
306 | struct capicardparams param; | ||
307 | int retval; | ||
308 | |||
309 | if (pci_enable_device(pdev) < 0) { | ||
310 | printk(KERN_ERR "b1pci: failed to enable AVM-B1\n"); | ||
311 | return -ENODEV; | ||
312 | } | ||
313 | param.irq = pdev->irq; | ||
314 | |||
315 | if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */ | ||
316 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
317 | pci_set_master(pdev); | ||
318 | #endif | ||
319 | param.membase = pci_resource_start(pdev, 0); | ||
320 | param.port = pci_resource_start(pdev, 2); | ||
321 | |||
322 | printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", | ||
323 | param.port, param.irq, param.membase); | ||
324 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
325 | retval = b1pciv4_probe(¶m, pdev); | ||
326 | #else | ||
327 | retval = b1pci_probe(¶m, pdev); | ||
328 | #endif | ||
329 | if (retval != 0) { | ||
330 | printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n", | ||
331 | param.port, param.irq, param.membase); | ||
332 | } | ||
333 | } else { | ||
334 | param.membase = 0; | ||
335 | param.port = pci_resource_start(pdev, 1); | ||
336 | |||
337 | printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", | ||
338 | param.port, param.irq); | ||
339 | retval = b1pci_probe(¶m, pdev); | ||
340 | if (retval != 0) { | ||
341 | printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n", | ||
342 | param.port, param.irq); | ||
343 | } | ||
344 | } | ||
345 | return retval; | ||
346 | } | ||
347 | |||
348 | static void __devexit b1pci_pci_remove(struct pci_dev *pdev) | ||
349 | { | ||
350 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
351 | avmcard *card = pci_get_drvdata(pdev); | ||
352 | |||
353 | if (card->dma) | ||
354 | b1pciv4_remove(pdev); | ||
355 | else | ||
356 | b1pci_remove(pdev); | ||
357 | #else | ||
358 | b1pci_remove(pdev); | ||
359 | #endif | ||
360 | } | ||
361 | |||
362 | static struct pci_driver b1pci_pci_driver = { | ||
363 | .name = "b1pci", | ||
364 | .id_table = b1pci_pci_tbl, | ||
365 | .probe = b1pci_pci_probe, | ||
366 | .remove = __devexit_p(b1pci_pci_remove), | ||
367 | }; | ||
368 | |||
369 | static struct capi_driver capi_driver_b1pci = { | ||
370 | .name = "b1pci", | ||
371 | .revision = "1.0", | ||
372 | }; | ||
373 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
374 | static struct capi_driver capi_driver_b1pciv4 = { | ||
375 | .name = "b1pciv4", | ||
376 | .revision = "1.0", | ||
377 | }; | ||
378 | #endif | ||
379 | |||
380 | static int __init b1pci_init(void) | ||
381 | { | ||
382 | char *p; | ||
383 | char rev[32]; | ||
384 | int err; | ||
385 | |||
386 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
387 | strlcpy(rev, p + 2, 32); | ||
388 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
389 | *(p-1) = 0; | ||
390 | } else | ||
391 | strcpy(rev, "1.0"); | ||
392 | |||
393 | |||
394 | err = pci_register_driver(&b1pci_pci_driver); | ||
395 | if (!err) { | ||
396 | strlcpy(capi_driver_b1pci.revision, rev, 32); | ||
397 | register_capi_driver(&capi_driver_b1pci); | ||
398 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
399 | strlcpy(capi_driver_b1pciv4.revision, rev, 32); | ||
400 | register_capi_driver(&capi_driver_b1pciv4); | ||
401 | #endif | ||
402 | printk(KERN_INFO "b1pci: revision %s\n", rev); | ||
403 | } | ||
404 | return err; | ||
405 | } | ||
406 | |||
407 | static void __exit b1pci_exit(void) | ||
408 | { | ||
409 | unregister_capi_driver(&capi_driver_b1pci); | ||
410 | #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 | ||
411 | unregister_capi_driver(&capi_driver_b1pciv4); | ||
412 | #endif | ||
413 | pci_unregister_driver(&b1pci_pci_driver); | ||
414 | } | ||
415 | |||
416 | module_init(b1pci_init); | ||
417 | module_exit(b1pci_exit); | ||
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c new file mode 100644 index 000000000000..9746cc5ffff8 --- /dev/null +++ b/drivers/isdn/hardware/avm/b1pcmcia.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM B1/M1/M2 PCMCIA-card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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 | #include <linux/kernel.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <linux/capi.h> | ||
22 | #include <linux/b1pcmcia.h> | ||
23 | #include <linux/isdn/capicmd.h> | ||
24 | #include <linux/isdn/capiutil.h> | ||
25 | #include <linux/isdn/capilli.h> | ||
26 | #include "avmcard.h" | ||
27 | |||
28 | /* ------------------------------------------------------------- */ | ||
29 | |||
30 | static char *revision = "$Revision: 1.1.2.2 $"; | ||
31 | |||
32 | /* ------------------------------------------------------------- */ | ||
33 | |||
34 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards"); | ||
35 | MODULE_AUTHOR("Carsten Paeth"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | /* ------------------------------------------------------------- */ | ||
39 | |||
40 | static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl) | ||
41 | { | ||
42 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
43 | avmcard *card = cinfo->card; | ||
44 | unsigned int port = card->port; | ||
45 | |||
46 | b1_reset(port); | ||
47 | b1_reset(port); | ||
48 | |||
49 | detach_capi_ctr(ctrl); | ||
50 | free_irq(card->irq, card); | ||
51 | b1_free_card(card); | ||
52 | } | ||
53 | |||
54 | /* ------------------------------------------------------------- */ | ||
55 | |||
56 | static LIST_HEAD(cards); | ||
57 | |||
58 | static char *b1pcmcia_procinfo(struct capi_ctr *ctrl); | ||
59 | |||
60 | static int b1pcmcia_add_card(unsigned int port, unsigned irq, | ||
61 | enum avmcardtype cardtype) | ||
62 | { | ||
63 | avmctrl_info *cinfo; | ||
64 | avmcard *card; | ||
65 | char *cardname; | ||
66 | int retval; | ||
67 | |||
68 | card = b1_alloc_card(1); | ||
69 | if (!card) { | ||
70 | printk(KERN_WARNING "b1pcmcia: no memory.\n"); | ||
71 | retval = -ENOMEM; | ||
72 | goto err; | ||
73 | } | ||
74 | cinfo = card->ctrlinfo; | ||
75 | |||
76 | switch (cardtype) { | ||
77 | case avm_m1: sprintf(card->name, "m1-%x", port); break; | ||
78 | case avm_m2: sprintf(card->name, "m2-%x", port); break; | ||
79 | default: sprintf(card->name, "b1pcmcia-%x", port); break; | ||
80 | } | ||
81 | card->port = port; | ||
82 | card->irq = irq; | ||
83 | card->cardtype = cardtype; | ||
84 | |||
85 | retval = request_irq(card->irq, b1_interrupt, 0, card->name, card); | ||
86 | if (retval) { | ||
87 | printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", | ||
88 | card->irq); | ||
89 | retval = -EBUSY; | ||
90 | goto err_free; | ||
91 | } | ||
92 | b1_reset(card->port); | ||
93 | if ((retval = b1_detect(card->port, card->cardtype)) != 0) { | ||
94 | printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n", | ||
95 | card->port, retval); | ||
96 | retval = -ENODEV; | ||
97 | goto err_free_irq; | ||
98 | } | ||
99 | b1_reset(card->port); | ||
100 | b1_getrevision(card); | ||
101 | |||
102 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
103 | cinfo->capi_ctrl.driver_name = "b1pcmcia"; | ||
104 | cinfo->capi_ctrl.driverdata = cinfo; | ||
105 | cinfo->capi_ctrl.register_appl = b1_register_appl; | ||
106 | cinfo->capi_ctrl.release_appl = b1_release_appl; | ||
107 | cinfo->capi_ctrl.send_message = b1_send_message; | ||
108 | cinfo->capi_ctrl.load_firmware = b1_load_firmware; | ||
109 | cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; | ||
110 | cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; | ||
111 | cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; | ||
112 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
113 | |||
114 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
115 | if (retval) { | ||
116 | printk(KERN_ERR "b1pcmcia: attach controller failed.\n"); | ||
117 | goto err_free_irq; | ||
118 | } | ||
119 | switch (cardtype) { | ||
120 | case avm_m1: cardname = "M1"; break; | ||
121 | case avm_m2: cardname = "M2"; break; | ||
122 | default : cardname = "B1 PCMCIA"; break; | ||
123 | } | ||
124 | |||
125 | printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n", | ||
126 | cardname, card->port, card->irq, card->revision); | ||
127 | |||
128 | list_add(&card->list, &cards); | ||
129 | return cinfo->capi_ctrl.cnr; | ||
130 | |||
131 | err_free_irq: | ||
132 | free_irq(card->irq, card); | ||
133 | err_free: | ||
134 | b1_free_card(card); | ||
135 | err: | ||
136 | return retval; | ||
137 | } | ||
138 | |||
139 | /* ------------------------------------------------------------- */ | ||
140 | |||
141 | static char *b1pcmcia_procinfo(struct capi_ctr *ctrl) | ||
142 | { | ||
143 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
144 | |||
145 | if (!cinfo) | ||
146 | return ""; | ||
147 | sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", | ||
148 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
149 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
150 | cinfo->card ? cinfo->card->port : 0x0, | ||
151 | cinfo->card ? cinfo->card->irq : 0, | ||
152 | cinfo->card ? cinfo->card->revision : 0 | ||
153 | ); | ||
154 | return cinfo->infobuf; | ||
155 | } | ||
156 | |||
157 | /* ------------------------------------------------------------- */ | ||
158 | |||
159 | int b1pcmcia_addcard_b1(unsigned int port, unsigned irq) | ||
160 | { | ||
161 | return b1pcmcia_add_card(port, irq, avm_b1pcmcia); | ||
162 | } | ||
163 | |||
164 | int b1pcmcia_addcard_m1(unsigned int port, unsigned irq) | ||
165 | { | ||
166 | return b1pcmcia_add_card(port, irq, avm_m1); | ||
167 | } | ||
168 | |||
169 | int b1pcmcia_addcard_m2(unsigned int port, unsigned irq) | ||
170 | { | ||
171 | return b1pcmcia_add_card(port, irq, avm_m2); | ||
172 | } | ||
173 | |||
174 | int b1pcmcia_delcard(unsigned int port, unsigned irq) | ||
175 | { | ||
176 | struct list_head *l; | ||
177 | avmcard *card; | ||
178 | |||
179 | list_for_each(l, &cards) { | ||
180 | card = list_entry(l, avmcard, list); | ||
181 | if (card->port == port && card->irq == irq) { | ||
182 | b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl); | ||
183 | return 0; | ||
184 | } | ||
185 | } | ||
186 | return -ESRCH; | ||
187 | } | ||
188 | |||
189 | EXPORT_SYMBOL(b1pcmcia_addcard_b1); | ||
190 | EXPORT_SYMBOL(b1pcmcia_addcard_m1); | ||
191 | EXPORT_SYMBOL(b1pcmcia_addcard_m2); | ||
192 | EXPORT_SYMBOL(b1pcmcia_delcard); | ||
193 | |||
194 | static struct capi_driver capi_driver_b1pcmcia = { | ||
195 | .name = "b1pcmcia", | ||
196 | .revision = "1.0", | ||
197 | }; | ||
198 | |||
199 | static int __init b1pcmcia_init(void) | ||
200 | { | ||
201 | char *p; | ||
202 | char rev[32]; | ||
203 | |||
204 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
205 | strlcpy(rev, p + 2, 32); | ||
206 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
207 | *(p-1) = 0; | ||
208 | } else | ||
209 | strcpy(rev, "1.0"); | ||
210 | |||
211 | strlcpy(capi_driver_b1pcmcia.revision, rev, 32); | ||
212 | register_capi_driver(&capi_driver_b1pcmcia); | ||
213 | printk(KERN_INFO "b1pci: revision %s\n", rev); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void __exit b1pcmcia_exit(void) | ||
219 | { | ||
220 | unregister_capi_driver(&capi_driver_b1pcmcia); | ||
221 | } | ||
222 | |||
223 | module_init(b1pcmcia_init); | ||
224 | module_exit(b1pcmcia_exit); | ||
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c new file mode 100644 index 000000000000..fa6b93b1a42d --- /dev/null +++ b/drivers/isdn/hardware/avm/c4.c | |||
@@ -0,0 +1,1310 @@ | |||
1 | /* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM C4 & C2 card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/capi.h> | ||
22 | #include <linux/kernelcapi.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/isdn/capicmd.h> | ||
28 | #include <linux/isdn/capiutil.h> | ||
29 | #include <linux/isdn/capilli.h> | ||
30 | #include "avmcard.h" | ||
31 | |||
32 | #undef CONFIG_C4_DEBUG | ||
33 | #undef CONFIG_C4_POLLDEBUG | ||
34 | |||
35 | /* ------------------------------------------------------------- */ | ||
36 | |||
37 | static char *revision = "$Revision: 1.1.2.2 $"; | ||
38 | |||
39 | /* ------------------------------------------------------------- */ | ||
40 | |||
41 | static int suppress_pollack; | ||
42 | |||
43 | static struct pci_device_id c4_pci_tbl[] = { | ||
44 | { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 }, | ||
45 | { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 0, 0, (unsigned long)2 }, | ||
46 | { } /* Terminating entry */ | ||
47 | }; | ||
48 | |||
49 | MODULE_DEVICE_TABLE(pci, c4_pci_tbl); | ||
50 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards"); | ||
51 | MODULE_AUTHOR("Carsten Paeth"); | ||
52 | MODULE_LICENSE("GPL"); | ||
53 | MODULE_PARM(suppress_pollack, "0-1i"); | ||
54 | |||
55 | /* ------------------------------------------------------------- */ | ||
56 | |||
57 | static void c4_dispatch_tx(avmcard *card); | ||
58 | |||
59 | /* ------------------------------------------------------------- */ | ||
60 | |||
61 | #define DC21285_DRAM_A0MR 0x40000000 | ||
62 | #define DC21285_DRAM_A1MR 0x40004000 | ||
63 | #define DC21285_DRAM_A2MR 0x40008000 | ||
64 | #define DC21285_DRAM_A3MR 0x4000C000 | ||
65 | |||
66 | #define CAS_OFFSET 0x88 | ||
67 | |||
68 | #define DC21285_ARMCSR_BASE 0x42000000 | ||
69 | |||
70 | #define PCI_OUT_INT_STATUS 0x30 | ||
71 | #define PCI_OUT_INT_MASK 0x34 | ||
72 | #define MAILBOX_0 0x50 | ||
73 | #define MAILBOX_1 0x54 | ||
74 | #define MAILBOX_2 0x58 | ||
75 | #define MAILBOX_3 0x5C | ||
76 | #define DOORBELL 0x60 | ||
77 | #define DOORBELL_SETUP 0x64 | ||
78 | |||
79 | #define CHAN_1_CONTROL 0x90 | ||
80 | #define CHAN_2_CONTROL 0xB0 | ||
81 | #define DRAM_TIMING 0x10C | ||
82 | #define DRAM_ADDR_SIZE_0 0x110 | ||
83 | #define DRAM_ADDR_SIZE_1 0x114 | ||
84 | #define DRAM_ADDR_SIZE_2 0x118 | ||
85 | #define DRAM_ADDR_SIZE_3 0x11C | ||
86 | #define SA_CONTROL 0x13C | ||
87 | #define XBUS_CYCLE 0x148 | ||
88 | #define XBUS_STROBE 0x14C | ||
89 | #define DBELL_PCI_MASK 0x150 | ||
90 | #define DBELL_SA_MASK 0x154 | ||
91 | |||
92 | #define SDRAM_SIZE 0x1000000 | ||
93 | |||
94 | /* ------------------------------------------------------------- */ | ||
95 | |||
96 | #define MBOX_PEEK_POKE MAILBOX_0 | ||
97 | |||
98 | #define DBELL_ADDR 0x01 | ||
99 | #define DBELL_DATA 0x02 | ||
100 | #define DBELL_RNWR 0x40 | ||
101 | #define DBELL_INIT 0x80 | ||
102 | |||
103 | /* ------------------------------------------------------------- */ | ||
104 | |||
105 | #define MBOX_UP_ADDR MAILBOX_0 | ||
106 | #define MBOX_UP_LEN MAILBOX_1 | ||
107 | #define MBOX_DOWN_ADDR MAILBOX_2 | ||
108 | #define MBOX_DOWN_LEN MAILBOX_3 | ||
109 | |||
110 | #define DBELL_UP_HOST 0x00000100 | ||
111 | #define DBELL_UP_ARM 0x00000200 | ||
112 | #define DBELL_DOWN_HOST 0x00000400 | ||
113 | #define DBELL_DOWN_ARM 0x00000800 | ||
114 | #define DBELL_RESET_HOST 0x40000000 | ||
115 | #define DBELL_RESET_ARM 0x80000000 | ||
116 | |||
117 | /* ------------------------------------------------------------- */ | ||
118 | |||
119 | #define DRAM_TIMING_DEF 0x001A01A5 | ||
120 | #define DRAM_AD_SZ_DEF0 0x00000045 | ||
121 | #define DRAM_AD_SZ_NULL 0x00000000 | ||
122 | |||
123 | #define SA_CTL_ALLRIGHT 0x64AA0271 | ||
124 | |||
125 | #define INIT_XBUS_CYCLE 0x100016DB | ||
126 | #define INIT_XBUS_STROBE 0xF1F1F1F1 | ||
127 | |||
128 | /* ------------------------------------------------------------- */ | ||
129 | |||
130 | #define RESET_TIMEOUT (15*HZ) /* 15 sec */ | ||
131 | #define PEEK_POKE_TIMEOUT (HZ/10) /* 0.1 sec */ | ||
132 | |||
133 | /* ------------------------------------------------------------- */ | ||
134 | |||
135 | #define c4outmeml(addr, value) writel(value, addr) | ||
136 | #define c4inmeml(addr) readl(addr) | ||
137 | #define c4outmemw(addr, value) writew(value, addr) | ||
138 | #define c4inmemw(addr) readw(addr) | ||
139 | #define c4outmemb(addr, value) writeb(value, addr) | ||
140 | #define c4inmemb(addr) readb(addr) | ||
141 | |||
142 | /* ------------------------------------------------------------- */ | ||
143 | |||
144 | static inline int wait_for_doorbell(avmcard *card, unsigned long t) | ||
145 | { | ||
146 | unsigned long stop; | ||
147 | |||
148 | stop = jiffies + t; | ||
149 | while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { | ||
150 | if (!time_before(jiffies, stop)) | ||
151 | return -1; | ||
152 | mb(); | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int c4_poke(avmcard *card, unsigned long off, unsigned long value) | ||
158 | { | ||
159 | |||
160 | if (wait_for_doorbell(card, HZ/10) < 0) | ||
161 | return -1; | ||
162 | |||
163 | c4outmeml(card->mbase+MBOX_PEEK_POKE, off); | ||
164 | c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); | ||
165 | |||
166 | if (wait_for_doorbell(card, HZ/10) < 0) | ||
167 | return -1; | ||
168 | |||
169 | c4outmeml(card->mbase+MBOX_PEEK_POKE, value); | ||
170 | c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep) | ||
176 | { | ||
177 | if (wait_for_doorbell(card, HZ/10) < 0) | ||
178 | return -1; | ||
179 | |||
180 | c4outmeml(card->mbase+MBOX_PEEK_POKE, off); | ||
181 | c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR); | ||
182 | |||
183 | if (wait_for_doorbell(card, HZ/10) < 0) | ||
184 | return -1; | ||
185 | |||
186 | *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* ------------------------------------------------------------- */ | ||
192 | |||
193 | static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file) | ||
194 | { | ||
195 | u32 val; | ||
196 | unsigned char *dp; | ||
197 | u_int left; | ||
198 | u32 loadoff = 0; | ||
199 | |||
200 | dp = t4file->data; | ||
201 | left = t4file->len; | ||
202 | while (left >= sizeof(u32)) { | ||
203 | if (t4file->user) { | ||
204 | if (copy_from_user(&val, dp, sizeof(val))) | ||
205 | return -EFAULT; | ||
206 | } else { | ||
207 | memcpy(&val, dp, sizeof(val)); | ||
208 | } | ||
209 | if (c4_poke(card, loadoff, val)) { | ||
210 | printk(KERN_ERR "%s: corrupted firmware file ?\n", | ||
211 | card->name); | ||
212 | return -EIO; | ||
213 | } | ||
214 | left -= sizeof(u32); | ||
215 | dp += sizeof(u32); | ||
216 | loadoff += sizeof(u32); | ||
217 | } | ||
218 | if (left) { | ||
219 | val = 0; | ||
220 | if (t4file->user) { | ||
221 | if (copy_from_user(&val, dp, left)) | ||
222 | return -EFAULT; | ||
223 | } else { | ||
224 | memcpy(&val, dp, left); | ||
225 | } | ||
226 | if (c4_poke(card, loadoff, val)) { | ||
227 | printk(KERN_ERR "%s: corrupted firmware file ?\n", | ||
228 | card->name); | ||
229 | return -EIO; | ||
230 | } | ||
231 | } | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | /* ------------------------------------------------------------- */ | ||
236 | |||
237 | static inline void _put_byte(void **pp, u8 val) | ||
238 | { | ||
239 | u8 *s = *pp; | ||
240 | *s++ = val; | ||
241 | *pp = s; | ||
242 | } | ||
243 | |||
244 | static inline void _put_word(void **pp, u32 val) | ||
245 | { | ||
246 | u8 *s = *pp; | ||
247 | *s++ = val & 0xff; | ||
248 | *s++ = (val >> 8) & 0xff; | ||
249 | *s++ = (val >> 16) & 0xff; | ||
250 | *s++ = (val >> 24) & 0xff; | ||
251 | *pp = s; | ||
252 | } | ||
253 | |||
254 | static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) | ||
255 | { | ||
256 | unsigned i = len; | ||
257 | _put_word(pp, i); | ||
258 | while (i-- > 0) | ||
259 | _put_byte(pp, *dp++); | ||
260 | } | ||
261 | |||
262 | static inline u8 _get_byte(void **pp) | ||
263 | { | ||
264 | u8 *s = *pp; | ||
265 | u8 val; | ||
266 | val = *s++; | ||
267 | *pp = s; | ||
268 | return val; | ||
269 | } | ||
270 | |||
271 | static inline u32 _get_word(void **pp) | ||
272 | { | ||
273 | u8 *s = *pp; | ||
274 | u32 val; | ||
275 | val = *s++; | ||
276 | val |= (*s++ << 8); | ||
277 | val |= (*s++ << 16); | ||
278 | val |= (*s++ << 24); | ||
279 | *pp = s; | ||
280 | return val; | ||
281 | } | ||
282 | |||
283 | static inline u32 _get_slice(void **pp, unsigned char *dp) | ||
284 | { | ||
285 | unsigned int len, i; | ||
286 | |||
287 | len = i = _get_word(pp); | ||
288 | while (i-- > 0) *dp++ = _get_byte(pp); | ||
289 | return len; | ||
290 | } | ||
291 | |||
292 | /* ------------------------------------------------------------- */ | ||
293 | |||
294 | static void c4_reset(avmcard *card) | ||
295 | { | ||
296 | unsigned long stop; | ||
297 | |||
298 | c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); | ||
299 | |||
300 | stop = jiffies + HZ*10; | ||
301 | while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { | ||
302 | if (!time_before(jiffies, stop)) | ||
303 | return; | ||
304 | c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); | ||
305 | mb(); | ||
306 | } | ||
307 | |||
308 | c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); | ||
309 | c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); | ||
310 | } | ||
311 | |||
312 | /* ------------------------------------------------------------- */ | ||
313 | |||
314 | static int c4_detect(avmcard *card) | ||
315 | { | ||
316 | unsigned long stop, dummy; | ||
317 | |||
318 | c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); | ||
319 | if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c) | ||
320 | return 1; | ||
321 | |||
322 | c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); | ||
323 | |||
324 | stop = jiffies + HZ*10; | ||
325 | while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { | ||
326 | if (!time_before(jiffies, stop)) | ||
327 | return 2; | ||
328 | c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); | ||
329 | mb(); | ||
330 | } | ||
331 | |||
332 | c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); | ||
333 | c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); | ||
334 | |||
335 | c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa); | ||
336 | if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3; | ||
337 | |||
338 | c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55); | ||
339 | if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4; | ||
340 | |||
341 | if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5; | ||
342 | if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6; | ||
343 | if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT)) | ||
344 | return 7; | ||
345 | if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE)) | ||
346 | return 8; | ||
347 | if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE)) | ||
348 | return 8; | ||
349 | if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9; | ||
350 | |||
351 | mdelay(1); | ||
352 | |||
353 | if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10; | ||
354 | if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11; | ||
355 | if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12; | ||
356 | if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13; | ||
357 | |||
358 | if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14; | ||
359 | if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15; | ||
360 | if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16; | ||
361 | if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17; | ||
362 | |||
363 | mdelay(1); | ||
364 | |||
365 | if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF)) | ||
366 | return 18; | ||
367 | |||
368 | if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0)) | ||
369 | return 19; | ||
370 | if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL)) | ||
371 | return 20; | ||
372 | if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL)) | ||
373 | return 21; | ||
374 | if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL)) | ||
375 | return 22; | ||
376 | |||
377 | /* Transputer test */ | ||
378 | |||
379 | if ( c4_poke(card, 0x000000, 0x11111111) | ||
380 | || c4_poke(card, 0x400000, 0x22222222) | ||
381 | || c4_poke(card, 0x800000, 0x33333333) | ||
382 | || c4_poke(card, 0xC00000, 0x44444444)) | ||
383 | return 23; | ||
384 | |||
385 | if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111 | ||
386 | || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222 | ||
387 | || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333 | ||
388 | || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444) | ||
389 | return 24; | ||
390 | |||
391 | if ( c4_poke(card, 0x000000, 0x55555555) | ||
392 | || c4_poke(card, 0x400000, 0x66666666) | ||
393 | || c4_poke(card, 0x800000, 0x77777777) | ||
394 | || c4_poke(card, 0xC00000, 0x88888888)) | ||
395 | return 25; | ||
396 | |||
397 | if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555 | ||
398 | || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666 | ||
399 | || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777 | ||
400 | || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888) | ||
401 | return 26; | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | /* ------------------------------------------------------------- */ | ||
407 | |||
408 | static void c4_dispatch_tx(avmcard *card) | ||
409 | { | ||
410 | avmcard_dmainfo *dma = card->dma; | ||
411 | struct sk_buff *skb; | ||
412 | u8 cmd, subcmd; | ||
413 | u16 len; | ||
414 | u32 txlen; | ||
415 | void *p; | ||
416 | |||
417 | |||
418 | if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ | ||
419 | return; | ||
420 | } | ||
421 | |||
422 | skb = skb_dequeue(&dma->send_queue); | ||
423 | if (!skb) { | ||
424 | #ifdef CONFIG_C4_DEBUG | ||
425 | printk(KERN_DEBUG "%s: tx underrun\n", card->name); | ||
426 | #endif | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | len = CAPIMSG_LEN(skb->data); | ||
431 | |||
432 | if (len) { | ||
433 | cmd = CAPIMSG_COMMAND(skb->data); | ||
434 | subcmd = CAPIMSG_SUBCOMMAND(skb->data); | ||
435 | |||
436 | p = dma->sendbuf.dmabuf; | ||
437 | |||
438 | if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { | ||
439 | u16 dlen = CAPIMSG_DATALEN(skb->data); | ||
440 | _put_byte(&p, SEND_DATA_B3_REQ); | ||
441 | _put_slice(&p, skb->data, len); | ||
442 | _put_slice(&p, skb->data + len, dlen); | ||
443 | } else { | ||
444 | _put_byte(&p, SEND_MESSAGE); | ||
445 | _put_slice(&p, skb->data, len); | ||
446 | } | ||
447 | txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; | ||
448 | #ifdef CONFIG_C4_DEBUG | ||
449 | printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); | ||
450 | #endif | ||
451 | } else { | ||
452 | txlen = skb->len-2; | ||
453 | #ifdef CONFIG_C4_POLLDEBUG | ||
454 | if (skb->data[2] == SEND_POLLACK) | ||
455 | printk(KERN_INFO "%s: ack to c4\n", card->name); | ||
456 | #endif | ||
457 | #ifdef CONFIG_C4_DEBUG | ||
458 | printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", | ||
459 | card->name, skb->data[2], txlen); | ||
460 | #endif | ||
461 | memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2); | ||
462 | } | ||
463 | txlen = (txlen + 3) & ~3; | ||
464 | |||
465 | c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr); | ||
466 | c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen); | ||
467 | |||
468 | card->csr |= DBELL_DOWN_ARM; | ||
469 | |||
470 | c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM); | ||
471 | |||
472 | dev_kfree_skb_any(skb); | ||
473 | } | ||
474 | |||
475 | /* ------------------------------------------------------------- */ | ||
476 | |||
477 | static void queue_pollack(avmcard *card) | ||
478 | { | ||
479 | struct sk_buff *skb; | ||
480 | void *p; | ||
481 | |||
482 | skb = alloc_skb(3, GFP_ATOMIC); | ||
483 | if (!skb) { | ||
484 | printk(KERN_CRIT "%s: no memory, lost poll ack\n", | ||
485 | card->name); | ||
486 | return; | ||
487 | } | ||
488 | p = skb->data; | ||
489 | _put_byte(&p, 0); | ||
490 | _put_byte(&p, 0); | ||
491 | _put_byte(&p, SEND_POLLACK); | ||
492 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
493 | |||
494 | skb_queue_tail(&card->dma->send_queue, skb); | ||
495 | c4_dispatch_tx(card); | ||
496 | } | ||
497 | |||
498 | /* ------------------------------------------------------------- */ | ||
499 | |||
500 | static void c4_handle_rx(avmcard *card) | ||
501 | { | ||
502 | avmcard_dmainfo *dma = card->dma; | ||
503 | struct capi_ctr *ctrl; | ||
504 | avmctrl_info *cinfo; | ||
505 | struct sk_buff *skb; | ||
506 | void *p = dma->recvbuf.dmabuf; | ||
507 | u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; | ||
508 | u8 b1cmd = _get_byte(&p); | ||
509 | u32 cidx; | ||
510 | |||
511 | |||
512 | #ifdef CONFIG_C4_DEBUG | ||
513 | printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name, | ||
514 | b1cmd, (unsigned long)dma->recvlen); | ||
515 | #endif | ||
516 | |||
517 | switch (b1cmd) { | ||
518 | case RECEIVE_DATA_B3_IND: | ||
519 | |||
520 | ApplId = (unsigned) _get_word(&p); | ||
521 | MsgLen = _get_slice(&p, card->msgbuf); | ||
522 | DataB3Len = _get_slice(&p, card->databuf); | ||
523 | cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; | ||
524 | if (cidx >= card->nlogcontr) cidx = 0; | ||
525 | ctrl = &card->ctrlinfo[cidx].capi_ctrl; | ||
526 | |||
527 | if (MsgLen < 30) { /* not CAPI 64Bit */ | ||
528 | memset(card->msgbuf+MsgLen, 0, 30-MsgLen); | ||
529 | MsgLen = 30; | ||
530 | CAPIMSG_SETLEN(card->msgbuf, 30); | ||
531 | } | ||
532 | if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { | ||
533 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
534 | card->name); | ||
535 | } else { | ||
536 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
537 | memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); | ||
538 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
539 | } | ||
540 | break; | ||
541 | |||
542 | case RECEIVE_MESSAGE: | ||
543 | |||
544 | ApplId = (unsigned) _get_word(&p); | ||
545 | MsgLen = _get_slice(&p, card->msgbuf); | ||
546 | cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; | ||
547 | if (cidx >= card->nlogcontr) cidx = 0; | ||
548 | cinfo = &card->ctrlinfo[cidx]; | ||
549 | ctrl = &card->ctrlinfo[cidx].capi_ctrl; | ||
550 | |||
551 | if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { | ||
552 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
553 | card->name); | ||
554 | } else { | ||
555 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
556 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) | ||
557 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | ||
558 | CAPIMSG_NCCI(skb->data), | ||
559 | CAPIMSG_MSGID(skb->data)); | ||
560 | |||
561 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
562 | } | ||
563 | break; | ||
564 | |||
565 | case RECEIVE_NEW_NCCI: | ||
566 | |||
567 | ApplId = _get_word(&p); | ||
568 | NCCI = _get_word(&p); | ||
569 | WindowSize = _get_word(&p); | ||
570 | cidx = (NCCI&0x7f) - card->cardnr; | ||
571 | if (cidx >= card->nlogcontr) cidx = 0; | ||
572 | |||
573 | capilib_new_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI, WindowSize); | ||
574 | |||
575 | break; | ||
576 | |||
577 | case RECEIVE_FREE_NCCI: | ||
578 | |||
579 | ApplId = _get_word(&p); | ||
580 | NCCI = _get_word(&p); | ||
581 | |||
582 | if (NCCI != 0xffffffff) { | ||
583 | cidx = (NCCI&0x7f) - card->cardnr; | ||
584 | if (cidx >= card->nlogcontr) cidx = 0; | ||
585 | capilib_free_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI); | ||
586 | } | ||
587 | break; | ||
588 | |||
589 | case RECEIVE_START: | ||
590 | #ifdef CONFIG_C4_POLLDEBUG | ||
591 | printk(KERN_INFO "%s: poll from c4\n", card->name); | ||
592 | #endif | ||
593 | if (!suppress_pollack) | ||
594 | queue_pollack(card); | ||
595 | for (cidx=0; cidx < card->nr_controllers; cidx++) { | ||
596 | ctrl = &card->ctrlinfo[cidx].capi_ctrl; | ||
597 | capi_ctr_resume_output(ctrl); | ||
598 | } | ||
599 | break; | ||
600 | |||
601 | case RECEIVE_STOP: | ||
602 | for (cidx=0; cidx < card->nr_controllers; cidx++) { | ||
603 | ctrl = &card->ctrlinfo[cidx].capi_ctrl; | ||
604 | capi_ctr_suspend_output(ctrl); | ||
605 | } | ||
606 | break; | ||
607 | |||
608 | case RECEIVE_INIT: | ||
609 | |||
610 | cidx = card->nlogcontr; | ||
611 | if (cidx >= card->nr_controllers) { | ||
612 | printk(KERN_ERR "%s: card with %d controllers ??\n", | ||
613 | card->name, cidx+1); | ||
614 | break; | ||
615 | } | ||
616 | card->nlogcontr++; | ||
617 | cinfo = &card->ctrlinfo[cidx]; | ||
618 | ctrl = &cinfo->capi_ctrl; | ||
619 | cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); | ||
620 | b1_parse_version(cinfo); | ||
621 | printk(KERN_INFO "%s: %s-card (%s) now active\n", | ||
622 | card->name, | ||
623 | cinfo->version[VER_CARDTYPE], | ||
624 | cinfo->version[VER_DRIVER]); | ||
625 | capi_ctr_ready(&cinfo->capi_ctrl); | ||
626 | break; | ||
627 | |||
628 | case RECEIVE_TASK_READY: | ||
629 | ApplId = (unsigned) _get_word(&p); | ||
630 | MsgLen = _get_slice(&p, card->msgbuf); | ||
631 | card->msgbuf[MsgLen] = 0; | ||
632 | while ( MsgLen > 0 | ||
633 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
634 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
635 | card->msgbuf[MsgLen-1] = 0; | ||
636 | MsgLen--; | ||
637 | } | ||
638 | printk(KERN_INFO "%s: task %d \"%s\" ready.\n", | ||
639 | card->name, ApplId, card->msgbuf); | ||
640 | break; | ||
641 | |||
642 | case RECEIVE_DEBUGMSG: | ||
643 | MsgLen = _get_slice(&p, card->msgbuf); | ||
644 | card->msgbuf[MsgLen] = 0; | ||
645 | while ( MsgLen > 0 | ||
646 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
647 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
648 | card->msgbuf[MsgLen-1] = 0; | ||
649 | MsgLen--; | ||
650 | } | ||
651 | printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); | ||
652 | break; | ||
653 | |||
654 | default: | ||
655 | printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n", | ||
656 | card->name, b1cmd); | ||
657 | return; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | /* ------------------------------------------------------------- */ | ||
662 | |||
663 | static irqreturn_t c4_handle_interrupt(avmcard *card) | ||
664 | { | ||
665 | unsigned long flags; | ||
666 | u32 status; | ||
667 | |||
668 | spin_lock_irqsave(&card->lock, flags); | ||
669 | status = c4inmeml(card->mbase+DOORBELL); | ||
670 | |||
671 | if (status & DBELL_RESET_HOST) { | ||
672 | u_int i; | ||
673 | c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); | ||
674 | spin_unlock_irqrestore(&card->lock, flags); | ||
675 | if (card->nlogcontr == 0) | ||
676 | return IRQ_HANDLED; | ||
677 | printk(KERN_ERR "%s: unexpected reset\n", card->name); | ||
678 | for (i=0; i < card->nr_controllers; i++) { | ||
679 | avmctrl_info *cinfo = &card->ctrlinfo[i]; | ||
680 | memset(cinfo->version, 0, sizeof(cinfo->version)); | ||
681 | capilib_release(&cinfo->ncci_head); | ||
682 | capi_ctr_reseted(&cinfo->capi_ctrl); | ||
683 | } | ||
684 | card->nlogcontr = 0; | ||
685 | return IRQ_HANDLED; | ||
686 | } | ||
687 | |||
688 | status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); | ||
689 | if (!status) { | ||
690 | spin_unlock_irqrestore(&card->lock, flags); | ||
691 | return IRQ_HANDLED; | ||
692 | } | ||
693 | c4outmeml(card->mbase+DOORBELL, status); | ||
694 | |||
695 | if ((status & DBELL_UP_HOST) != 0) { | ||
696 | card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN); | ||
697 | c4outmeml(card->mbase+MBOX_UP_LEN, 0); | ||
698 | c4_handle_rx(card); | ||
699 | card->dma->recvlen = 0; | ||
700 | c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); | ||
701 | c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); | ||
702 | } | ||
703 | |||
704 | if ((status & DBELL_DOWN_HOST) != 0) { | ||
705 | card->csr &= ~DBELL_DOWN_ARM; | ||
706 | c4_dispatch_tx(card); | ||
707 | } else if (card->csr & DBELL_DOWN_HOST) { | ||
708 | if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) { | ||
709 | card->csr &= ~DBELL_DOWN_ARM; | ||
710 | c4_dispatch_tx(card); | ||
711 | } | ||
712 | } | ||
713 | spin_unlock_irqrestore(&card->lock, flags); | ||
714 | return IRQ_HANDLED; | ||
715 | } | ||
716 | |||
717 | static irqreturn_t c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs) | ||
718 | { | ||
719 | avmcard *card = devptr; | ||
720 | |||
721 | return c4_handle_interrupt(card); | ||
722 | } | ||
723 | |||
724 | /* ------------------------------------------------------------- */ | ||
725 | |||
726 | static void c4_send_init(avmcard *card) | ||
727 | { | ||
728 | struct sk_buff *skb; | ||
729 | void *p; | ||
730 | |||
731 | skb = alloc_skb(15, GFP_ATOMIC); | ||
732 | if (!skb) { | ||
733 | printk(KERN_CRIT "%s: no memory, lost register appl.\n", | ||
734 | card->name); | ||
735 | return; | ||
736 | } | ||
737 | p = skb->data; | ||
738 | _put_byte(&p, 0); | ||
739 | _put_byte(&p, 0); | ||
740 | _put_byte(&p, SEND_INIT); | ||
741 | _put_word(&p, CAPI_MAXAPPL); | ||
742 | _put_word(&p, AVM_NCCI_PER_CHANNEL*30); | ||
743 | _put_word(&p, card->cardnr - 1); | ||
744 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
745 | |||
746 | skb_queue_tail(&card->dma->send_queue, skb); | ||
747 | c4_dispatch_tx(card); | ||
748 | } | ||
749 | |||
750 | static int queue_sendconfigword(avmcard *card, u32 val) | ||
751 | { | ||
752 | struct sk_buff *skb; | ||
753 | void *p; | ||
754 | |||
755 | skb = alloc_skb(3+4, GFP_ATOMIC); | ||
756 | if (!skb) { | ||
757 | printk(KERN_CRIT "%s: no memory, send config\n", | ||
758 | card->name); | ||
759 | return -ENOMEM; | ||
760 | } | ||
761 | p = skb->data; | ||
762 | _put_byte(&p, 0); | ||
763 | _put_byte(&p, 0); | ||
764 | _put_byte(&p, SEND_CONFIG); | ||
765 | _put_word(&p, val); | ||
766 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
767 | |||
768 | skb_queue_tail(&card->dma->send_queue, skb); | ||
769 | c4_dispatch_tx(card); | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static int queue_sendconfig(avmcard *card, char cval[4]) | ||
774 | { | ||
775 | struct sk_buff *skb; | ||
776 | unsigned long flags; | ||
777 | void *p; | ||
778 | |||
779 | skb = alloc_skb(3+4, GFP_ATOMIC); | ||
780 | if (!skb) { | ||
781 | printk(KERN_CRIT "%s: no memory, send config\n", | ||
782 | card->name); | ||
783 | return -ENOMEM; | ||
784 | } | ||
785 | p = skb->data; | ||
786 | _put_byte(&p, 0); | ||
787 | _put_byte(&p, 0); | ||
788 | _put_byte(&p, SEND_CONFIG); | ||
789 | _put_byte(&p, cval[0]); | ||
790 | _put_byte(&p, cval[1]); | ||
791 | _put_byte(&p, cval[2]); | ||
792 | _put_byte(&p, cval[3]); | ||
793 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
794 | |||
795 | skb_queue_tail(&card->dma->send_queue, skb); | ||
796 | |||
797 | spin_lock_irqsave(&card->lock, flags); | ||
798 | c4_dispatch_tx(card); | ||
799 | spin_unlock_irqrestore(&card->lock, flags); | ||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static int c4_send_config(avmcard *card, capiloaddatapart * config) | ||
804 | { | ||
805 | u8 val[4]; | ||
806 | unsigned char *dp; | ||
807 | u_int left; | ||
808 | int retval; | ||
809 | |||
810 | if ((retval = queue_sendconfigword(card, 1)) != 0) | ||
811 | return retval; | ||
812 | if ((retval = queue_sendconfigword(card, config->len)) != 0) | ||
813 | return retval; | ||
814 | |||
815 | dp = config->data; | ||
816 | left = config->len; | ||
817 | while (left >= sizeof(u32)) { | ||
818 | if (config->user) { | ||
819 | if (copy_from_user(val, dp, sizeof(val))) | ||
820 | return -EFAULT; | ||
821 | } else { | ||
822 | memcpy(val, dp, sizeof(val)); | ||
823 | } | ||
824 | if ((retval = queue_sendconfig(card, val)) != 0) | ||
825 | return retval; | ||
826 | left -= sizeof(val); | ||
827 | dp += sizeof(val); | ||
828 | } | ||
829 | if (left) { | ||
830 | memset(val, 0, sizeof(val)); | ||
831 | if (config->user) { | ||
832 | if (copy_from_user(&val, dp, left)) | ||
833 | return -EFAULT; | ||
834 | } else { | ||
835 | memcpy(&val, dp, left); | ||
836 | } | ||
837 | if ((retval = queue_sendconfig(card, val)) != 0) | ||
838 | return retval; | ||
839 | } | ||
840 | |||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) | ||
845 | { | ||
846 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
847 | avmcard *card = cinfo->card; | ||
848 | int retval; | ||
849 | |||
850 | if ((retval = c4_load_t4file(card, &data->firmware))) { | ||
851 | printk(KERN_ERR "%s: failed to load t4file!!\n", | ||
852 | card->name); | ||
853 | c4_reset(card); | ||
854 | return retval; | ||
855 | } | ||
856 | |||
857 | card->csr = 0; | ||
858 | c4outmeml(card->mbase+MBOX_UP_LEN, 0); | ||
859 | c4outmeml(card->mbase+MBOX_DOWN_LEN, 0); | ||
860 | c4outmeml(card->mbase+DOORBELL, DBELL_INIT); | ||
861 | mdelay(1); | ||
862 | c4outmeml(card->mbase+DOORBELL, | ||
863 | DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST); | ||
864 | |||
865 | c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08); | ||
866 | |||
867 | card->dma->recvlen = 0; | ||
868 | c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr); | ||
869 | c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); | ||
870 | c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); | ||
871 | |||
872 | if (data->configuration.len > 0 && data->configuration.data) { | ||
873 | retval = c4_send_config(card, &data->configuration); | ||
874 | if (retval) { | ||
875 | printk(KERN_ERR "%s: failed to set config!!\n", | ||
876 | card->name); | ||
877 | c4_reset(card); | ||
878 | return retval; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | c4_send_init(card); | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | |||
888 | void c4_reset_ctr(struct capi_ctr *ctrl) | ||
889 | { | ||
890 | avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; | ||
891 | avmctrl_info *cinfo; | ||
892 | u_int i; | ||
893 | unsigned long flags; | ||
894 | |||
895 | spin_lock_irqsave(&card->lock, flags); | ||
896 | |||
897 | c4_reset(card); | ||
898 | |||
899 | spin_unlock_irqrestore(&card->lock, flags); | ||
900 | |||
901 | for (i=0; i < card->nr_controllers; i++) { | ||
902 | cinfo = &card->ctrlinfo[i]; | ||
903 | memset(cinfo->version, 0, sizeof(cinfo->version)); | ||
904 | capi_ctr_reseted(&cinfo->capi_ctrl); | ||
905 | } | ||
906 | card->nlogcontr = 0; | ||
907 | } | ||
908 | |||
909 | static void c4_remove(struct pci_dev *pdev) | ||
910 | { | ||
911 | avmcard *card = pci_get_drvdata(pdev); | ||
912 | avmctrl_info *cinfo; | ||
913 | u_int i; | ||
914 | |||
915 | if (!card) | ||
916 | return; | ||
917 | |||
918 | c4_reset(card); | ||
919 | |||
920 | for (i=0; i < card->nr_controllers; i++) { | ||
921 | cinfo = &card->ctrlinfo[i]; | ||
922 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
923 | } | ||
924 | |||
925 | free_irq(card->irq, card); | ||
926 | iounmap(card->mbase); | ||
927 | release_region(card->port, AVMB1_PORTLEN); | ||
928 | avmcard_dma_free(card->dma); | ||
929 | pci_set_drvdata(pdev, NULL); | ||
930 | b1_free_card(card); | ||
931 | } | ||
932 | |||
933 | /* ------------------------------------------------------------- */ | ||
934 | |||
935 | |||
936 | void c4_register_appl(struct capi_ctr *ctrl, | ||
937 | u16 appl, | ||
938 | capi_register_params *rp) | ||
939 | { | ||
940 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
941 | avmcard *card = cinfo->card; | ||
942 | struct sk_buff *skb; | ||
943 | int want = rp->level3cnt; | ||
944 | unsigned long flags; | ||
945 | int nconn; | ||
946 | void *p; | ||
947 | |||
948 | if (ctrl->cnr == card->cardnr) { | ||
949 | |||
950 | if (want > 0) nconn = want; | ||
951 | else nconn = ctrl->profile.nbchannel * 4 * -want; | ||
952 | if (nconn == 0) nconn = ctrl->profile.nbchannel * 4; | ||
953 | |||
954 | skb = alloc_skb(23, GFP_ATOMIC); | ||
955 | if (!skb) { | ||
956 | printk(KERN_CRIT "%s: no memory, lost register appl.\n", | ||
957 | card->name); | ||
958 | return; | ||
959 | } | ||
960 | p = skb->data; | ||
961 | _put_byte(&p, 0); | ||
962 | _put_byte(&p, 0); | ||
963 | _put_byte(&p, SEND_REGISTER); | ||
964 | _put_word(&p, appl); | ||
965 | _put_word(&p, 1024 * (nconn+1)); | ||
966 | _put_word(&p, nconn); | ||
967 | _put_word(&p, rp->datablkcnt); | ||
968 | _put_word(&p, rp->datablklen); | ||
969 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
970 | |||
971 | skb_queue_tail(&card->dma->send_queue, skb); | ||
972 | |||
973 | spin_lock_irqsave(&card->lock, flags); | ||
974 | c4_dispatch_tx(card); | ||
975 | spin_unlock_irqrestore(&card->lock, flags); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | /* ------------------------------------------------------------- */ | ||
980 | |||
981 | void c4_release_appl(struct capi_ctr *ctrl, u16 appl) | ||
982 | { | ||
983 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
984 | avmcard *card = cinfo->card; | ||
985 | unsigned long flags; | ||
986 | struct sk_buff *skb; | ||
987 | void *p; | ||
988 | |||
989 | capilib_release_appl(&cinfo->ncci_head, appl); | ||
990 | |||
991 | if (ctrl->cnr == card->cardnr) { | ||
992 | skb = alloc_skb(7, GFP_ATOMIC); | ||
993 | if (!skb) { | ||
994 | printk(KERN_CRIT "%s: no memory, lost release appl.\n", | ||
995 | card->name); | ||
996 | return; | ||
997 | } | ||
998 | p = skb->data; | ||
999 | _put_byte(&p, 0); | ||
1000 | _put_byte(&p, 0); | ||
1001 | _put_byte(&p, SEND_RELEASE); | ||
1002 | _put_word(&p, appl); | ||
1003 | |||
1004 | skb_put(skb, (u8 *)p - (u8 *)skb->data); | ||
1005 | skb_queue_tail(&card->dma->send_queue, skb); | ||
1006 | spin_lock_irqsave(&card->lock, flags); | ||
1007 | c4_dispatch_tx(card); | ||
1008 | spin_unlock_irqrestore(&card->lock, flags); | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | /* ------------------------------------------------------------- */ | ||
1013 | |||
1014 | |||
1015 | static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | ||
1016 | { | ||
1017 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
1018 | avmcard *card = cinfo->card; | ||
1019 | u16 retval = CAPI_NOERROR; | ||
1020 | unsigned long flags; | ||
1021 | |||
1022 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { | ||
1023 | retval = capilib_data_b3_req(&cinfo->ncci_head, | ||
1024 | CAPIMSG_APPID(skb->data), | ||
1025 | CAPIMSG_NCCI(skb->data), | ||
1026 | CAPIMSG_MSGID(skb->data)); | ||
1027 | } | ||
1028 | if (retval == CAPI_NOERROR) { | ||
1029 | skb_queue_tail(&card->dma->send_queue, skb); | ||
1030 | spin_lock_irqsave(&card->lock, flags); | ||
1031 | c4_dispatch_tx(card); | ||
1032 | spin_unlock_irqrestore(&card->lock, flags); | ||
1033 | } | ||
1034 | return retval; | ||
1035 | } | ||
1036 | |||
1037 | /* ------------------------------------------------------------- */ | ||
1038 | |||
1039 | static char *c4_procinfo(struct capi_ctr *ctrl) | ||
1040 | { | ||
1041 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
1042 | |||
1043 | if (!cinfo) | ||
1044 | return ""; | ||
1045 | sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", | ||
1046 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
1047 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
1048 | cinfo->card ? cinfo->card->port : 0x0, | ||
1049 | cinfo->card ? cinfo->card->irq : 0, | ||
1050 | cinfo->card ? cinfo->card->membase : 0 | ||
1051 | ); | ||
1052 | return cinfo->infobuf; | ||
1053 | } | ||
1054 | |||
1055 | static int c4_read_proc(char *page, char **start, off_t off, | ||
1056 | int count, int *eof, struct capi_ctr *ctrl) | ||
1057 | { | ||
1058 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
1059 | avmcard *card = cinfo->card; | ||
1060 | u8 flag; | ||
1061 | int len = 0; | ||
1062 | char *s; | ||
1063 | |||
1064 | len += sprintf(page+len, "%-16s %s\n", "name", card->name); | ||
1065 | len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); | ||
1066 | len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); | ||
1067 | len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); | ||
1068 | switch (card->cardtype) { | ||
1069 | case avm_b1isa: s = "B1 ISA"; break; | ||
1070 | case avm_b1pci: s = "B1 PCI"; break; | ||
1071 | case avm_b1pcmcia: s = "B1 PCMCIA"; break; | ||
1072 | case avm_m1: s = "M1"; break; | ||
1073 | case avm_m2: s = "M2"; break; | ||
1074 | case avm_t1isa: s = "T1 ISA (HEMA)"; break; | ||
1075 | case avm_t1pci: s = "T1 PCI"; break; | ||
1076 | case avm_c4: s = "C4"; break; | ||
1077 | case avm_c2: s = "C2"; break; | ||
1078 | default: s = "???"; break; | ||
1079 | } | ||
1080 | len += sprintf(page+len, "%-16s %s\n", "type", s); | ||
1081 | if ((s = cinfo->version[VER_DRIVER]) != 0) | ||
1082 | len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); | ||
1083 | if ((s = cinfo->version[VER_CARDTYPE]) != 0) | ||
1084 | len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); | ||
1085 | if ((s = cinfo->version[VER_SERIAL]) != 0) | ||
1086 | len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); | ||
1087 | |||
1088 | if (card->cardtype != avm_m1) { | ||
1089 | flag = ((u8 *)(ctrl->profile.manu))[3]; | ||
1090 | if (flag) | ||
1091 | len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", | ||
1092 | "protocol", | ||
1093 | (flag & 0x01) ? " DSS1" : "", | ||
1094 | (flag & 0x02) ? " CT1" : "", | ||
1095 | (flag & 0x04) ? " VN3" : "", | ||
1096 | (flag & 0x08) ? " NI1" : "", | ||
1097 | (flag & 0x10) ? " AUSTEL" : "", | ||
1098 | (flag & 0x20) ? " ESS" : "", | ||
1099 | (flag & 0x40) ? " 1TR6" : "" | ||
1100 | ); | ||
1101 | } | ||
1102 | if (card->cardtype != avm_m1) { | ||
1103 | flag = ((u8 *)(ctrl->profile.manu))[5]; | ||
1104 | if (flag) | ||
1105 | len += sprintf(page+len, "%-16s%s%s%s%s\n", | ||
1106 | "linetype", | ||
1107 | (flag & 0x01) ? " point to point" : "", | ||
1108 | (flag & 0x02) ? " point to multipoint" : "", | ||
1109 | (flag & 0x08) ? " leased line without D-channel" : "", | ||
1110 | (flag & 0x04) ? " leased line with D-channel" : "" | ||
1111 | ); | ||
1112 | } | ||
1113 | len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); | ||
1114 | |||
1115 | if (off+count >= len) | ||
1116 | *eof = 1; | ||
1117 | if (len < off) | ||
1118 | return 0; | ||
1119 | *start = page + off; | ||
1120 | return ((count < len-off) ? count : len-off); | ||
1121 | } | ||
1122 | |||
1123 | /* ------------------------------------------------------------- */ | ||
1124 | |||
1125 | static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, | ||
1126 | int nr_controllers) | ||
1127 | { | ||
1128 | avmcard *card; | ||
1129 | avmctrl_info *cinfo; | ||
1130 | int retval; | ||
1131 | int i; | ||
1132 | |||
1133 | card = b1_alloc_card(nr_controllers); | ||
1134 | if (!card) { | ||
1135 | printk(KERN_WARNING "c4: no memory.\n"); | ||
1136 | retval = -ENOMEM; | ||
1137 | goto err; | ||
1138 | } | ||
1139 | card->dma = avmcard_dma_alloc("c4", dev, 2048+128, 2048+128); | ||
1140 | if (!card->dma) { | ||
1141 | printk(KERN_WARNING "c4: no memory.\n"); | ||
1142 | retval = -ENOMEM; | ||
1143 | goto err_free; | ||
1144 | } | ||
1145 | |||
1146 | sprintf(card->name, "c%d-%x", nr_controllers, p->port); | ||
1147 | card->port = p->port; | ||
1148 | card->irq = p->irq; | ||
1149 | card->membase = p->membase; | ||
1150 | card->cardtype = (nr_controllers == 4) ? avm_c4 : avm_c2; | ||
1151 | |||
1152 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
1153 | printk(KERN_WARNING "c4: ports 0x%03x-0x%03x in use.\n", | ||
1154 | card->port, card->port + AVMB1_PORTLEN); | ||
1155 | retval = -EBUSY; | ||
1156 | goto err_free_dma; | ||
1157 | } | ||
1158 | |||
1159 | card->mbase = ioremap(card->membase, 128); | ||
1160 | if (card->mbase == 0) { | ||
1161 | printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n", | ||
1162 | card->membase); | ||
1163 | retval = -EIO; | ||
1164 | goto err_release_region; | ||
1165 | } | ||
1166 | |||
1167 | retval = c4_detect(card); | ||
1168 | if (retval != 0) { | ||
1169 | printk(KERN_NOTICE "c4: NO card at 0x%x error(%d)\n", | ||
1170 | card->port, retval); | ||
1171 | retval = -EIO; | ||
1172 | goto err_unmap; | ||
1173 | } | ||
1174 | c4_reset(card); | ||
1175 | |||
1176 | retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card); | ||
1177 | if (retval) { | ||
1178 | printk(KERN_ERR "c4: unable to get IRQ %d.\n",card->irq); | ||
1179 | retval = -EBUSY; | ||
1180 | goto err_unmap; | ||
1181 | } | ||
1182 | |||
1183 | for (i=0; i < nr_controllers ; i++) { | ||
1184 | cinfo = &card->ctrlinfo[i]; | ||
1185 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
1186 | cinfo->capi_ctrl.driver_name = "c4"; | ||
1187 | cinfo->capi_ctrl.driverdata = cinfo; | ||
1188 | cinfo->capi_ctrl.register_appl = c4_register_appl; | ||
1189 | cinfo->capi_ctrl.release_appl = c4_release_appl; | ||
1190 | cinfo->capi_ctrl.send_message = c4_send_message; | ||
1191 | cinfo->capi_ctrl.load_firmware = c4_load_firmware; | ||
1192 | cinfo->capi_ctrl.reset_ctr = c4_reset_ctr; | ||
1193 | cinfo->capi_ctrl.procinfo = c4_procinfo; | ||
1194 | cinfo->capi_ctrl.ctr_read_proc = c4_read_proc; | ||
1195 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
1196 | |||
1197 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
1198 | if (retval) { | ||
1199 | printk(KERN_ERR "c4: attach controller failed (%d).\n", i); | ||
1200 | for (i--; i >= 0; i--) { | ||
1201 | cinfo = &card->ctrlinfo[i]; | ||
1202 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
1203 | } | ||
1204 | goto err_free_irq; | ||
1205 | } | ||
1206 | if (i == 0) | ||
1207 | card->cardnr = cinfo->capi_ctrl.cnr; | ||
1208 | } | ||
1209 | |||
1210 | printk(KERN_INFO "c4: AVM C%d at i/o %#x, irq %d, mem %#lx\n", | ||
1211 | nr_controllers, card->port, card->irq, | ||
1212 | card->membase); | ||
1213 | pci_set_drvdata(dev, card); | ||
1214 | return 0; | ||
1215 | |||
1216 | err_free_irq: | ||
1217 | free_irq(card->irq, card); | ||
1218 | err_unmap: | ||
1219 | iounmap(card->mbase); | ||
1220 | err_release_region: | ||
1221 | release_region(card->port, AVMB1_PORTLEN); | ||
1222 | err_free_dma: | ||
1223 | avmcard_dma_free(card->dma); | ||
1224 | err_free: | ||
1225 | b1_free_card(card); | ||
1226 | err: | ||
1227 | return retval; | ||
1228 | } | ||
1229 | |||
1230 | /* ------------------------------------------------------------- */ | ||
1231 | |||
1232 | static int __devinit c4_probe(struct pci_dev *dev, | ||
1233 | const struct pci_device_id *ent) | ||
1234 | { | ||
1235 | int nr = ent->driver_data; | ||
1236 | int retval = 0; | ||
1237 | struct capicardparams param; | ||
1238 | |||
1239 | if (pci_enable_device(dev) < 0) { | ||
1240 | printk(KERN_ERR "c4: failed to enable AVM-C%d\n", nr); | ||
1241 | return -ENODEV; | ||
1242 | } | ||
1243 | pci_set_master(dev); | ||
1244 | |||
1245 | param.port = pci_resource_start(dev, 1); | ||
1246 | param.irq = dev->irq; | ||
1247 | param.membase = pci_resource_start(dev, 0); | ||
1248 | |||
1249 | printk(KERN_INFO "c4: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n", | ||
1250 | nr, param.port, param.irq, param.membase); | ||
1251 | |||
1252 | retval = c4_add_card(¶m, dev, nr); | ||
1253 | if (retval != 0) { | ||
1254 | printk(KERN_ERR "c4: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n", | ||
1255 | nr, param.port, param.irq, param.membase); | ||
1256 | return -ENODEV; | ||
1257 | } | ||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | static struct pci_driver c4_pci_driver = { | ||
1262 | .name = "c4", | ||
1263 | .id_table = c4_pci_tbl, | ||
1264 | .probe = c4_probe, | ||
1265 | .remove = c4_remove, | ||
1266 | }; | ||
1267 | |||
1268 | static struct capi_driver capi_driver_c2 = { | ||
1269 | .name = "c2", | ||
1270 | .revision = "1.0", | ||
1271 | }; | ||
1272 | |||
1273 | static struct capi_driver capi_driver_c4 = { | ||
1274 | .name = "c4", | ||
1275 | .revision = "1.0", | ||
1276 | }; | ||
1277 | |||
1278 | static int __init c4_init(void) | ||
1279 | { | ||
1280 | char *p; | ||
1281 | char rev[32]; | ||
1282 | int err; | ||
1283 | |||
1284 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
1285 | strlcpy(rev, p + 2, 32); | ||
1286 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
1287 | *(p-1) = 0; | ||
1288 | } else | ||
1289 | strcpy(rev, "1.0"); | ||
1290 | |||
1291 | err = pci_register_driver(&c4_pci_driver); | ||
1292 | if (!err) { | ||
1293 | strlcpy(capi_driver_c2.revision, rev, 32); | ||
1294 | register_capi_driver(&capi_driver_c2); | ||
1295 | strlcpy(capi_driver_c4.revision, rev, 32); | ||
1296 | register_capi_driver(&capi_driver_c4); | ||
1297 | printk(KERN_INFO "c4: revision %s\n", rev); | ||
1298 | } | ||
1299 | return err; | ||
1300 | } | ||
1301 | |||
1302 | static void __exit c4_exit(void) | ||
1303 | { | ||
1304 | unregister_capi_driver(&capi_driver_c2); | ||
1305 | unregister_capi_driver(&capi_driver_c4); | ||
1306 | pci_unregister_driver(&c4_pci_driver); | ||
1307 | } | ||
1308 | |||
1309 | module_init(c4_init); | ||
1310 | module_exit(c4_exit); | ||
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c new file mode 100644 index 000000000000..cb9d9cee2a64 --- /dev/null +++ b/drivers/isdn/hardware/avm/t1isa.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM T1 HEMA-card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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 | #include <linux/kernel.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/capi.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/kernelcapi.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <linux/isdn/capicmd.h> | ||
26 | #include <linux/isdn/capiutil.h> | ||
27 | #include <linux/isdn/capilli.h> | ||
28 | #include "avmcard.h" | ||
29 | |||
30 | /* ------------------------------------------------------------- */ | ||
31 | |||
32 | static char *revision = "$Revision: 1.1.2.3 $"; | ||
33 | |||
34 | /* ------------------------------------------------------------- */ | ||
35 | |||
36 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card"); | ||
37 | MODULE_AUTHOR("Carsten Paeth"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | |||
40 | /* ------------------------------------------------------------- */ | ||
41 | |||
42 | static int hema_irq_table[16] = | ||
43 | {0, | ||
44 | 0, | ||
45 | 0, | ||
46 | 0x80, /* irq 3 */ | ||
47 | 0, | ||
48 | 0x90, /* irq 5 */ | ||
49 | 0, | ||
50 | 0xA0, /* irq 7 */ | ||
51 | 0, | ||
52 | 0xB0, /* irq 9 */ | ||
53 | 0xC0, /* irq 10 */ | ||
54 | 0xD0, /* irq 11 */ | ||
55 | 0xE0, /* irq 12 */ | ||
56 | 0, | ||
57 | 0, | ||
58 | 0xF0, /* irq 15 */ | ||
59 | }; | ||
60 | |||
61 | static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr) | ||
62 | { | ||
63 | unsigned char cregs[8]; | ||
64 | unsigned char reverse_cardnr; | ||
65 | unsigned char dummy; | ||
66 | int i; | ||
67 | |||
68 | reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1) | ||
69 | | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3); | ||
70 | cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf); | ||
71 | cregs[1] = 0x00; /* fast & slow link connected to CON1 */ | ||
72 | cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */ | ||
73 | cregs[3] = 0; | ||
74 | cregs[4] = 0x11; /* zero wait state */ | ||
75 | cregs[5] = hema_irq_table[irq & 0xf]; | ||
76 | cregs[6] = 0; | ||
77 | cregs[7] = 0; | ||
78 | |||
79 | /* | ||
80 | * no one else should use the ISA bus in this moment, | ||
81 | * but no function there to prevent this :-( | ||
82 | * save_flags(flags); cli(); | ||
83 | */ | ||
84 | |||
85 | /* board reset */ | ||
86 | t1outp(base, T1_RESETBOARD, 0xf); | ||
87 | mdelay(100); | ||
88 | dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */ | ||
89 | |||
90 | /* write config */ | ||
91 | dummy = (base >> 4) & 0xff; | ||
92 | for (i=1;i<=0xf;i++) t1outp(base, i, dummy); | ||
93 | t1outp(base, HEMA_PAL_ID & 0xf, dummy); | ||
94 | t1outp(base, HEMA_PAL_ID >> 4, cregs[0]); | ||
95 | for(i=1;i<7;i++) t1outp(base, 0, cregs[i]); | ||
96 | t1outp(base, ((base >> 4)) & 0x3, cregs[7]); | ||
97 | /* restore_flags(flags); */ | ||
98 | |||
99 | mdelay(100); | ||
100 | t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); | ||
101 | t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); | ||
102 | mdelay(10); | ||
103 | t1outp(base, T1_FASTLINK+T1_RESETLINK, 1); | ||
104 | t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1); | ||
105 | mdelay(100); | ||
106 | t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); | ||
107 | t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); | ||
108 | mdelay(10); | ||
109 | t1outp(base, T1_FASTLINK+T1_ANALYSE, 0); | ||
110 | mdelay(5); | ||
111 | t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0); | ||
112 | |||
113 | if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */ | ||
114 | return 1; | ||
115 | if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */ | ||
116 | return 2; | ||
117 | if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0) | ||
118 | return 3; | ||
119 | if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70) | ||
120 | return 4; | ||
121 | if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0) | ||
122 | return 5; | ||
123 | if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1) | ||
124 | return 6; | ||
125 | if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */ | ||
126 | return 7; | ||
127 | if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0) | ||
128 | return 8; | ||
129 | if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0) | ||
130 | return 9; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static irqreturn_t t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) | ||
135 | { | ||
136 | avmcard *card = devptr; | ||
137 | avmctrl_info *cinfo = &card->ctrlinfo[0]; | ||
138 | struct capi_ctr *ctrl = &cinfo->capi_ctrl; | ||
139 | unsigned char b1cmd; | ||
140 | struct sk_buff *skb; | ||
141 | |||
142 | unsigned ApplId; | ||
143 | unsigned MsgLen; | ||
144 | unsigned DataB3Len; | ||
145 | unsigned NCCI; | ||
146 | unsigned WindowSize; | ||
147 | unsigned long flags; | ||
148 | |||
149 | spin_lock_irqsave(&card->lock, flags); | ||
150 | |||
151 | while (b1_rx_full(card->port)) { | ||
152 | |||
153 | b1cmd = b1_get_byte(card->port); | ||
154 | |||
155 | switch (b1cmd) { | ||
156 | |||
157 | case RECEIVE_DATA_B3_IND: | ||
158 | |||
159 | ApplId = (unsigned) b1_get_word(card->port); | ||
160 | MsgLen = t1_get_slice(card->port, card->msgbuf); | ||
161 | DataB3Len = t1_get_slice(card->port, card->databuf); | ||
162 | spin_unlock_irqrestore(&card->lock, flags); | ||
163 | |||
164 | if (MsgLen < 30) { /* not CAPI 64Bit */ | ||
165 | memset(card->msgbuf+MsgLen, 0, 30-MsgLen); | ||
166 | MsgLen = 30; | ||
167 | CAPIMSG_SETLEN(card->msgbuf, 30); | ||
168 | } | ||
169 | if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { | ||
170 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
171 | card->name); | ||
172 | } else { | ||
173 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
174 | memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); | ||
175 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
176 | } | ||
177 | break; | ||
178 | |||
179 | case RECEIVE_MESSAGE: | ||
180 | |||
181 | ApplId = (unsigned) b1_get_word(card->port); | ||
182 | MsgLen = t1_get_slice(card->port, card->msgbuf); | ||
183 | spin_unlock_irqrestore(&card->lock, flags); | ||
184 | if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { | ||
185 | printk(KERN_ERR "%s: incoming packet dropped\n", | ||
186 | card->name); | ||
187 | } else { | ||
188 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | ||
189 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3) | ||
190 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | ||
191 | CAPIMSG_NCCI(skb->data), | ||
192 | CAPIMSG_MSGID(skb->data)); | ||
193 | |||
194 | capi_ctr_handle_message(ctrl, ApplId, skb); | ||
195 | } | ||
196 | break; | ||
197 | |||
198 | case RECEIVE_NEW_NCCI: | ||
199 | |||
200 | ApplId = b1_get_word(card->port); | ||
201 | NCCI = b1_get_word(card->port); | ||
202 | WindowSize = b1_get_word(card->port); | ||
203 | spin_unlock_irqrestore(&card->lock, flags); | ||
204 | |||
205 | capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); | ||
206 | |||
207 | break; | ||
208 | |||
209 | case RECEIVE_FREE_NCCI: | ||
210 | |||
211 | ApplId = b1_get_word(card->port); | ||
212 | NCCI = b1_get_word(card->port); | ||
213 | spin_unlock_irqrestore(&card->lock, flags); | ||
214 | |||
215 | if (NCCI != 0xffffffff) | ||
216 | capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); | ||
217 | |||
218 | break; | ||
219 | |||
220 | case RECEIVE_START: | ||
221 | b1_put_byte(card->port, SEND_POLLACK); | ||
222 | spin_unlock_irqrestore(&card->lock, flags); | ||
223 | capi_ctr_resume_output(ctrl); | ||
224 | break; | ||
225 | |||
226 | case RECEIVE_STOP: | ||
227 | spin_unlock_irqrestore(&card->lock, flags); | ||
228 | capi_ctr_suspend_output(ctrl); | ||
229 | break; | ||
230 | |||
231 | case RECEIVE_INIT: | ||
232 | |||
233 | cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf); | ||
234 | spin_unlock_irqrestore(&card->lock, flags); | ||
235 | b1_parse_version(cinfo); | ||
236 | printk(KERN_INFO "%s: %s-card (%s) now active\n", | ||
237 | card->name, | ||
238 | cinfo->version[VER_CARDTYPE], | ||
239 | cinfo->version[VER_DRIVER]); | ||
240 | capi_ctr_ready(ctrl); | ||
241 | break; | ||
242 | |||
243 | case RECEIVE_TASK_READY: | ||
244 | ApplId = (unsigned) b1_get_word(card->port); | ||
245 | MsgLen = t1_get_slice(card->port, card->msgbuf); | ||
246 | spin_unlock_irqrestore(&card->lock, flags); | ||
247 | card->msgbuf[MsgLen] = 0; | ||
248 | while ( MsgLen > 0 | ||
249 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
250 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
251 | card->msgbuf[MsgLen-1] = 0; | ||
252 | MsgLen--; | ||
253 | } | ||
254 | printk(KERN_INFO "%s: task %d \"%s\" ready.\n", | ||
255 | card->name, ApplId, card->msgbuf); | ||
256 | break; | ||
257 | |||
258 | case RECEIVE_DEBUGMSG: | ||
259 | MsgLen = t1_get_slice(card->port, card->msgbuf); | ||
260 | spin_unlock_irqrestore(&card->lock, flags); | ||
261 | card->msgbuf[MsgLen] = 0; | ||
262 | while ( MsgLen > 0 | ||
263 | && ( card->msgbuf[MsgLen-1] == '\n' | ||
264 | || card->msgbuf[MsgLen-1] == '\r')) { | ||
265 | card->msgbuf[MsgLen-1] = 0; | ||
266 | MsgLen--; | ||
267 | } | ||
268 | printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); | ||
269 | break; | ||
270 | |||
271 | |||
272 | case 0xff: | ||
273 | spin_unlock_irqrestore(&card->lock, flags); | ||
274 | printk(KERN_ERR "%s: card reseted ?\n", card->name); | ||
275 | return IRQ_HANDLED; | ||
276 | default: | ||
277 | spin_unlock_irqrestore(&card->lock, flags); | ||
278 | printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", | ||
279 | card->name, b1cmd); | ||
280 | return IRQ_NONE; | ||
281 | } | ||
282 | } | ||
283 | return IRQ_HANDLED; | ||
284 | } | ||
285 | |||
286 | /* ------------------------------------------------------------- */ | ||
287 | |||
288 | static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) | ||
289 | { | ||
290 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
291 | avmcard *card = cinfo->card; | ||
292 | unsigned int port = card->port; | ||
293 | unsigned long flags; | ||
294 | int retval; | ||
295 | |||
296 | t1_disable_irq(port); | ||
297 | b1_reset(port); | ||
298 | |||
299 | if ((retval = b1_load_t4file(card, &data->firmware))) { | ||
300 | b1_reset(port); | ||
301 | printk(KERN_ERR "%s: failed to load t4file!!\n", | ||
302 | card->name); | ||
303 | return retval; | ||
304 | } | ||
305 | |||
306 | if (data->configuration.len > 0 && data->configuration.data) { | ||
307 | if ((retval = b1_load_config(card, &data->configuration))) { | ||
308 | b1_reset(port); | ||
309 | printk(KERN_ERR "%s: failed to load config!!\n", | ||
310 | card->name); | ||
311 | return retval; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | if (!b1_loaded(card)) { | ||
316 | printk(KERN_ERR "%s: failed to load t4file.\n", card->name); | ||
317 | return -EIO; | ||
318 | } | ||
319 | |||
320 | spin_lock_irqsave(&card->lock, flags); | ||
321 | b1_setinterrupt(port, card->irq, card->cardtype); | ||
322 | b1_put_byte(port, SEND_INIT); | ||
323 | b1_put_word(port, CAPI_MAXAPPL); | ||
324 | b1_put_word(port, AVM_NCCI_PER_CHANNEL*30); | ||
325 | b1_put_word(port, ctrl->cnr - 1); | ||
326 | spin_unlock_irqrestore(&card->lock, flags); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | void t1isa_reset_ctr(struct capi_ctr *ctrl) | ||
332 | { | ||
333 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
334 | avmcard *card = cinfo->card; | ||
335 | unsigned int port = card->port; | ||
336 | |||
337 | t1_disable_irq(port); | ||
338 | b1_reset(port); | ||
339 | b1_reset(port); | ||
340 | |||
341 | memset(cinfo->version, 0, sizeof(cinfo->version)); | ||
342 | capilib_release(&cinfo->ncci_head); | ||
343 | capi_ctr_reseted(ctrl); | ||
344 | } | ||
345 | |||
346 | static void t1isa_remove(struct pci_dev *pdev) | ||
347 | { | ||
348 | avmctrl_info *cinfo = pci_get_drvdata(pdev); | ||
349 | avmcard *card; | ||
350 | |||
351 | if (!cinfo) | ||
352 | return; | ||
353 | |||
354 | card = cinfo->card; | ||
355 | |||
356 | t1_disable_irq(card->port); | ||
357 | b1_reset(card->port); | ||
358 | b1_reset(card->port); | ||
359 | t1_reset(card->port); | ||
360 | |||
361 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
362 | free_irq(card->irq, card); | ||
363 | release_region(card->port, AVMB1_PORTLEN); | ||
364 | b1_free_card(card); | ||
365 | } | ||
366 | |||
367 | /* ------------------------------------------------------------- */ | ||
368 | |||
369 | static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); | ||
370 | static char *t1isa_procinfo(struct capi_ctr *ctrl); | ||
371 | |||
372 | static int t1isa_probe(struct pci_dev *pdev, int cardnr) | ||
373 | { | ||
374 | avmctrl_info *cinfo; | ||
375 | avmcard *card; | ||
376 | int retval; | ||
377 | |||
378 | card = b1_alloc_card(1); | ||
379 | if (!card) { | ||
380 | printk(KERN_WARNING "t1isa: no memory.\n"); | ||
381 | retval = -ENOMEM; | ||
382 | goto err; | ||
383 | } | ||
384 | |||
385 | cinfo = card->ctrlinfo; | ||
386 | card->port = pci_resource_start(pdev, 0); | ||
387 | card->irq = pdev->irq; | ||
388 | card->cardtype = avm_t1isa; | ||
389 | card->cardnr = cardnr; | ||
390 | sprintf(card->name, "t1isa-%x", card->port); | ||
391 | |||
392 | if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) { | ||
393 | printk(KERN_WARNING "t1isa: invalid port 0x%x.\n", card->port); | ||
394 | retval = -EINVAL; | ||
395 | goto err_free; | ||
396 | } | ||
397 | if (hema_irq_table[card->irq & 0xf] == 0) { | ||
398 | printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq); | ||
399 | retval = -EINVAL; | ||
400 | goto err_free; | ||
401 | } | ||
402 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
403 | printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n", | ||
404 | card->port, card->port + AVMB1_PORTLEN); | ||
405 | retval = -EBUSY; | ||
406 | goto err_free; | ||
407 | } | ||
408 | retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card); | ||
409 | if (retval) { | ||
410 | printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq); | ||
411 | retval = -EBUSY; | ||
412 | goto err_release_region; | ||
413 | } | ||
414 | |||
415 | if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) { | ||
416 | printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n", | ||
417 | card->port, retval); | ||
418 | retval = -ENODEV; | ||
419 | goto err_free_irq; | ||
420 | } | ||
421 | t1_disable_irq(card->port); | ||
422 | b1_reset(card->port); | ||
423 | |||
424 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
425 | cinfo->capi_ctrl.driver_name = "t1isa"; | ||
426 | cinfo->capi_ctrl.driverdata = cinfo; | ||
427 | cinfo->capi_ctrl.register_appl = b1_register_appl; | ||
428 | cinfo->capi_ctrl.release_appl = b1_release_appl; | ||
429 | cinfo->capi_ctrl.send_message = t1isa_send_message; | ||
430 | cinfo->capi_ctrl.load_firmware = t1isa_load_firmware; | ||
431 | cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr; | ||
432 | cinfo->capi_ctrl.procinfo = t1isa_procinfo; | ||
433 | cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; | ||
434 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
435 | |||
436 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
437 | if (retval) { | ||
438 | printk(KERN_INFO "t1isa: attach controller failed.\n"); | ||
439 | goto err_free_irq; | ||
440 | } | ||
441 | |||
442 | printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n", | ||
443 | card->port, card->irq, card->cardnr); | ||
444 | |||
445 | pci_set_drvdata(pdev, cinfo); | ||
446 | return 0; | ||
447 | |||
448 | err_free_irq: | ||
449 | free_irq(card->irq, card); | ||
450 | err_release_region: | ||
451 | release_region(card->port, AVMB1_PORTLEN); | ||
452 | err_free: | ||
453 | b1_free_card(card); | ||
454 | err: | ||
455 | return retval; | ||
456 | } | ||
457 | |||
458 | static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | ||
459 | { | ||
460 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
461 | avmcard *card = cinfo->card; | ||
462 | unsigned int port = card->port; | ||
463 | unsigned long flags; | ||
464 | u16 len = CAPIMSG_LEN(skb->data); | ||
465 | u8 cmd = CAPIMSG_COMMAND(skb->data); | ||
466 | u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); | ||
467 | u16 dlen, retval; | ||
468 | |||
469 | if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { | ||
470 | retval = capilib_data_b3_req(&cinfo->ncci_head, | ||
471 | CAPIMSG_APPID(skb->data), | ||
472 | CAPIMSG_NCCI(skb->data), | ||
473 | CAPIMSG_MSGID(skb->data)); | ||
474 | if (retval != CAPI_NOERROR) | ||
475 | return retval; | ||
476 | |||
477 | dlen = CAPIMSG_DATALEN(skb->data); | ||
478 | |||
479 | spin_lock_irqsave(&card->lock, flags); | ||
480 | b1_put_byte(port, SEND_DATA_B3_REQ); | ||
481 | t1_put_slice(port, skb->data, len); | ||
482 | t1_put_slice(port, skb->data + len, dlen); | ||
483 | spin_unlock_irqrestore(&card->lock, flags); | ||
484 | } else { | ||
485 | |||
486 | spin_lock_irqsave(&card->lock, flags); | ||
487 | b1_put_byte(port, SEND_MESSAGE); | ||
488 | t1_put_slice(port, skb->data, len); | ||
489 | spin_unlock_irqrestore(&card->lock, flags); | ||
490 | } | ||
491 | |||
492 | dev_kfree_skb_any(skb); | ||
493 | return CAPI_NOERROR; | ||
494 | } | ||
495 | /* ------------------------------------------------------------- */ | ||
496 | |||
497 | static char *t1isa_procinfo(struct capi_ctr *ctrl) | ||
498 | { | ||
499 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
500 | |||
501 | if (!cinfo) | ||
502 | return ""; | ||
503 | sprintf(cinfo->infobuf, "%s %s 0x%x %d %d", | ||
504 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
505 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
506 | cinfo->card ? cinfo->card->port : 0x0, | ||
507 | cinfo->card ? cinfo->card->irq : 0, | ||
508 | cinfo->card ? cinfo->card->cardnr : 0 | ||
509 | ); | ||
510 | return cinfo->infobuf; | ||
511 | } | ||
512 | |||
513 | |||
514 | /* ------------------------------------------------------------- */ | ||
515 | |||
516 | #define MAX_CARDS 4 | ||
517 | static struct pci_dev isa_dev[MAX_CARDS]; | ||
518 | static int io[MAX_CARDS]; | ||
519 | static int irq[MAX_CARDS]; | ||
520 | static int cardnr[MAX_CARDS]; | ||
521 | |||
522 | MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); | ||
523 | MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i"); | ||
524 | MODULE_PARM(cardnr, "1-" __MODULE_STRING(MAX_CARDS) "i"); | ||
525 | MODULE_PARM_DESC(io, "I/O base address(es)"); | ||
526 | MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); | ||
527 | MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)"); | ||
528 | |||
529 | static int t1isa_add_card(struct capi_driver *driver, capicardparams *data) | ||
530 | { | ||
531 | int i; | ||
532 | |||
533 | for (i = 0; i < MAX_CARDS; i++) { | ||
534 | if (isa_dev[i].resource[0].start) | ||
535 | continue; | ||
536 | |||
537 | isa_dev[i].resource[0].start = data->port; | ||
538 | isa_dev[i].irq = data->irq; | ||
539 | |||
540 | if (t1isa_probe(&isa_dev[i], data->cardnr) == 0) | ||
541 | return 0; | ||
542 | } | ||
543 | return -ENODEV; | ||
544 | } | ||
545 | |||
546 | static struct capi_driver capi_driver_t1isa = { | ||
547 | .name = "t1isa", | ||
548 | .revision = "1.0", | ||
549 | .add_card = t1isa_add_card, | ||
550 | }; | ||
551 | |||
552 | static int __init t1isa_init(void) | ||
553 | { | ||
554 | char rev[32]; | ||
555 | char *p; | ||
556 | int i; | ||
557 | |||
558 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
559 | strlcpy(rev, p + 2, 32); | ||
560 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
561 | *(p-1) = 0; | ||
562 | } else | ||
563 | strcpy(rev, "1.0"); | ||
564 | |||
565 | for (i = 0; i < MAX_CARDS; i++) { | ||
566 | if (!io[i]) | ||
567 | break; | ||
568 | |||
569 | isa_dev[i].resource[0].start = io[i]; | ||
570 | isa_dev[i].irq = irq[i]; | ||
571 | |||
572 | if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0) | ||
573 | return -ENODEV; | ||
574 | } | ||
575 | |||
576 | strlcpy(capi_driver_t1isa.revision, rev, 32); | ||
577 | register_capi_driver(&capi_driver_t1isa); | ||
578 | printk(KERN_INFO "t1isa: revision %s\n", rev); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static void __exit t1isa_exit(void) | ||
584 | { | ||
585 | int i; | ||
586 | |||
587 | for (i = 0; i < MAX_CARDS; i++) { | ||
588 | if (!io[i]) | ||
589 | break; | ||
590 | |||
591 | t1isa_remove(&isa_dev[i]); | ||
592 | } | ||
593 | } | ||
594 | |||
595 | module_init(t1isa_init); | ||
596 | module_exit(t1isa_exit); | ||
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c new file mode 100644 index 000000000000..2ceec8e8419f --- /dev/null +++ b/drivers/isdn/hardware/avm/t1pci.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ | ||
2 | * | ||
3 | * Module for AVM T1 PCI-card. | ||
4 | * | ||
5 | * Copyright 1999 by Carsten Paeth <calle@calle.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/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/capi.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/isdn/capicmd.h> | ||
25 | #include <linux/isdn/capiutil.h> | ||
26 | #include <linux/isdn/capilli.h> | ||
27 | #include "avmcard.h" | ||
28 | |||
29 | #undef CONFIG_T1PCI_DEBUG | ||
30 | #undef CONFIG_T1PCI_POLLDEBUG | ||
31 | |||
32 | /* ------------------------------------------------------------- */ | ||
33 | static char *revision = "$Revision: 1.1.2.2 $"; | ||
34 | /* ------------------------------------------------------------- */ | ||
35 | |||
36 | static struct pci_device_id t1pci_pci_tbl[] = { | ||
37 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID }, | ||
38 | { } /* Terminating entry */ | ||
39 | }; | ||
40 | |||
41 | MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl); | ||
42 | MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card"); | ||
43 | MODULE_AUTHOR("Carsten Paeth"); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | |||
46 | /* ------------------------------------------------------------- */ | ||
47 | |||
48 | static char *t1pci_procinfo(struct capi_ctr *ctrl); | ||
49 | |||
50 | static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) | ||
51 | { | ||
52 | avmcard *card; | ||
53 | avmctrl_info *cinfo; | ||
54 | int retval; | ||
55 | |||
56 | card = b1_alloc_card(1); | ||
57 | if (!card) { | ||
58 | printk(KERN_WARNING "t1pci: no memory.\n"); | ||
59 | retval = -ENOMEM; | ||
60 | goto err; | ||
61 | } | ||
62 | |||
63 | card->dma = avmcard_dma_alloc("t1pci", pdev, 2048+128, 2048+128); | ||
64 | if (!card->dma) { | ||
65 | printk(KERN_WARNING "t1pci: no memory.\n"); | ||
66 | retval = -ENOMEM; | ||
67 | goto err_free; | ||
68 | } | ||
69 | |||
70 | cinfo = card->ctrlinfo; | ||
71 | sprintf(card->name, "t1pci-%x", p->port); | ||
72 | card->port = p->port; | ||
73 | card->irq = p->irq; | ||
74 | card->membase = p->membase; | ||
75 | card->cardtype = avm_t1pci; | ||
76 | |||
77 | if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { | ||
78 | printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n", | ||
79 | card->port, card->port + AVMB1_PORTLEN); | ||
80 | retval = -EBUSY; | ||
81 | goto err_free_dma; | ||
82 | } | ||
83 | |||
84 | card->mbase = ioremap(card->membase, 64); | ||
85 | if (!card->mbase) { | ||
86 | printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n", | ||
87 | card->membase); | ||
88 | retval = -EIO; | ||
89 | goto err_release_region; | ||
90 | } | ||
91 | |||
92 | b1dma_reset(card); | ||
93 | |||
94 | retval = t1pci_detect(card); | ||
95 | if (retval != 0) { | ||
96 | if (retval < 6) | ||
97 | printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n", | ||
98 | card->port, retval); | ||
99 | else | ||
100 | printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n", | ||
101 | card->port, retval); | ||
102 | retval = -EIO; | ||
103 | goto err_unmap; | ||
104 | } | ||
105 | b1dma_reset(card); | ||
106 | |||
107 | retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); | ||
108 | if (retval) { | ||
109 | printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq); | ||
110 | retval = -EBUSY; | ||
111 | goto err_unmap; | ||
112 | } | ||
113 | |||
114 | cinfo->capi_ctrl.owner = THIS_MODULE; | ||
115 | cinfo->capi_ctrl.driver_name = "t1pci"; | ||
116 | cinfo->capi_ctrl.driverdata = cinfo; | ||
117 | cinfo->capi_ctrl.register_appl = b1dma_register_appl; | ||
118 | cinfo->capi_ctrl.release_appl = b1dma_release_appl; | ||
119 | cinfo->capi_ctrl.send_message = b1dma_send_message; | ||
120 | cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; | ||
121 | cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; | ||
122 | cinfo->capi_ctrl.procinfo = t1pci_procinfo; | ||
123 | cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; | ||
124 | strcpy(cinfo->capi_ctrl.name, card->name); | ||
125 | |||
126 | retval = attach_capi_ctr(&cinfo->capi_ctrl); | ||
127 | if (retval) { | ||
128 | printk(KERN_ERR "t1pci: attach controller failed.\n"); | ||
129 | retval = -EBUSY; | ||
130 | goto err_free_irq; | ||
131 | } | ||
132 | card->cardnr = cinfo->capi_ctrl.cnr; | ||
133 | |||
134 | printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n", | ||
135 | card->port, card->irq, card->membase); | ||
136 | |||
137 | pci_set_drvdata(pdev, card); | ||
138 | return 0; | ||
139 | |||
140 | err_free_irq: | ||
141 | free_irq(card->irq, card); | ||
142 | err_unmap: | ||
143 | iounmap(card->mbase); | ||
144 | err_release_region: | ||
145 | release_region(card->port, AVMB1_PORTLEN); | ||
146 | err_free_dma: | ||
147 | avmcard_dma_free(card->dma); | ||
148 | err_free: | ||
149 | b1_free_card(card); | ||
150 | err: | ||
151 | return retval; | ||
152 | } | ||
153 | |||
154 | /* ------------------------------------------------------------- */ | ||
155 | |||
156 | static void t1pci_remove(struct pci_dev *pdev) | ||
157 | { | ||
158 | avmcard *card = pci_get_drvdata(pdev); | ||
159 | avmctrl_info *cinfo = card->ctrlinfo; | ||
160 | |||
161 | b1dma_reset(card); | ||
162 | |||
163 | detach_capi_ctr(&cinfo->capi_ctrl); | ||
164 | free_irq(card->irq, card); | ||
165 | iounmap(card->mbase); | ||
166 | release_region(card->port, AVMB1_PORTLEN); | ||
167 | avmcard_dma_free(card->dma); | ||
168 | b1_free_card(card); | ||
169 | } | ||
170 | |||
171 | /* ------------------------------------------------------------- */ | ||
172 | |||
173 | static char *t1pci_procinfo(struct capi_ctr *ctrl) | ||
174 | { | ||
175 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | ||
176 | |||
177 | if (!cinfo) | ||
178 | return ""; | ||
179 | sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", | ||
180 | cinfo->cardname[0] ? cinfo->cardname : "-", | ||
181 | cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", | ||
182 | cinfo->card ? cinfo->card->port : 0x0, | ||
183 | cinfo->card ? cinfo->card->irq : 0, | ||
184 | cinfo->card ? cinfo->card->membase : 0 | ||
185 | ); | ||
186 | return cinfo->infobuf; | ||
187 | } | ||
188 | |||
189 | /* ------------------------------------------------------------- */ | ||
190 | |||
191 | static int __devinit t1pci_probe(struct pci_dev *dev, | ||
192 | const struct pci_device_id *ent) | ||
193 | { | ||
194 | struct capicardparams param; | ||
195 | int retval; | ||
196 | |||
197 | if (pci_enable_device(dev) < 0) { | ||
198 | printk(KERN_ERR "t1pci: failed to enable AVM-T1-PCI\n"); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | pci_set_master(dev); | ||
202 | |||
203 | param.port = pci_resource_start(dev, 1); | ||
204 | param.irq = dev->irq; | ||
205 | param.membase = pci_resource_start(dev, 0); | ||
206 | |||
207 | printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n", | ||
208 | param.port, param.irq, param.membase); | ||
209 | |||
210 | retval = t1pci_add_card(¶m, dev); | ||
211 | if (retval != 0) { | ||
212 | printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n", | ||
213 | param.port, param.irq, param.membase); | ||
214 | return -ENODEV; | ||
215 | } | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static struct pci_driver t1pci_pci_driver = { | ||
220 | .name = "t1pci", | ||
221 | .id_table = t1pci_pci_tbl, | ||
222 | .probe = t1pci_probe, | ||
223 | .remove = t1pci_remove, | ||
224 | }; | ||
225 | |||
226 | static struct capi_driver capi_driver_t1pci = { | ||
227 | .name = "t1pci", | ||
228 | .revision = "1.0", | ||
229 | }; | ||
230 | |||
231 | static int __init t1pci_init(void) | ||
232 | { | ||
233 | char *p; | ||
234 | char rev[32]; | ||
235 | int err; | ||
236 | |||
237 | if ((p = strchr(revision, ':')) != 0 && p[1]) { | ||
238 | strlcpy(rev, p + 2, 32); | ||
239 | if ((p = strchr(rev, '$')) != 0 && p > rev) | ||
240 | *(p-1) = 0; | ||
241 | } else | ||
242 | strcpy(rev, "1.0"); | ||
243 | |||
244 | err = pci_register_driver(&t1pci_pci_driver); | ||
245 | if (!err) { | ||
246 | strlcpy(capi_driver_t1pci.revision, rev, 32); | ||
247 | register_capi_driver(&capi_driver_t1pci); | ||
248 | printk(KERN_INFO "t1pci: revision %s\n", rev); | ||
249 | } | ||
250 | return err; | ||
251 | } | ||
252 | |||
253 | static void __exit t1pci_exit(void) | ||
254 | { | ||
255 | unregister_capi_driver(&capi_driver_t1pci); | ||
256 | pci_unregister_driver(&t1pci_pci_driver); | ||
257 | } | ||
258 | |||
259 | module_init(t1pci_init); | ||
260 | module_exit(t1pci_exit); | ||