diff options
Diffstat (limited to 'drivers/isdn')
54 files changed, 10290 insertions, 503 deletions
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 02bdca6f95c3..022a19452953 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig | |||
@@ -21,8 +21,6 @@ menuconfig ISDN | |||
21 | 21 | ||
22 | if ISDN | 22 | if ISDN |
23 | 23 | ||
24 | source "drivers/isdn/mISDN/Kconfig" | ||
25 | |||
26 | menuconfig ISDN_I4L | 24 | menuconfig ISDN_I4L |
27 | tristate "Old ISDN4Linux (deprecated)" | 25 | tristate "Old ISDN4Linux (deprecated)" |
28 | ---help--- | 26 | ---help--- |
@@ -41,9 +39,9 @@ menuconfig ISDN_I4L | |||
41 | It is still available, though, for use with adapters that are not | 39 | It is still available, though, for use with adapters that are not |
42 | supported by the new CAPI subsystem yet. | 40 | supported by the new CAPI subsystem yet. |
43 | 41 | ||
44 | if ISDN_I4L | 42 | source "drivers/isdn/mISDN/Kconfig" |
43 | |||
45 | source "drivers/isdn/i4l/Kconfig" | 44 | source "drivers/isdn/i4l/Kconfig" |
46 | endif | ||
47 | 45 | ||
48 | menuconfig ISDN_CAPI | 46 | menuconfig ISDN_CAPI |
49 | tristate "CAPI 2.0 subsystem" | 47 | tristate "CAPI 2.0 subsystem" |
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index 946c38cf6f8a..1f0a94906465 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c | |||
@@ -78,7 +78,6 @@ static actcapi_msgdsc valid_msg[] = { | |||
78 | #endif | 78 | #endif |
79 | {{ 0x00, 0x00}, NULL}, | 79 | {{ 0x00, 0x00}, NULL}, |
80 | }; | 80 | }; |
81 | #define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc)) | ||
82 | #define num_valid_imsg 27 /* MANUFACTURER_IND */ | 81 | #define num_valid_imsg 27 /* MANUFACTURER_IND */ |
83 | 82 | ||
84 | /* | 83 | /* |
@@ -1025,7 +1024,7 @@ actcapi_debug_msg(struct sk_buff *skb, int direction) | |||
1025 | #ifdef DEBUG_DUMP_SKB | 1024 | #ifdef DEBUG_DUMP_SKB |
1026 | dump_skb(skb); | 1025 | dump_skb(skb); |
1027 | #endif | 1026 | #endif |
1028 | for (i = 0; i < num_valid_msg; i++) | 1027 | for (i = 0; i < ARRAY_SIZE(valid_msg); i++) |
1029 | if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) && | 1028 | if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) && |
1030 | (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) { | 1029 | (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) { |
1031 | descr = valid_msg[i].description; | 1030 | descr = valid_msg[i].description; |
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index 8325022e2bed..f774e12bb64d 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c | |||
@@ -23,7 +23,6 @@ static unsigned short act2000_isa_ports[] = | |||
23 | 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380, | 23 | 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380, |
24 | 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60, | 24 | 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60, |
25 | }; | 25 | }; |
26 | #define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short)) | ||
27 | 26 | ||
28 | static act2000_card *cards = (act2000_card *) NULL; | 27 | static act2000_card *cards = (act2000_card *) NULL; |
29 | 28 | ||
@@ -686,21 +685,21 @@ act2000_addcard(int bus, int port, int irq, char *id) | |||
686 | * This may result in more than one card detected. | 685 | * This may result in more than one card detected. |
687 | */ | 686 | */ |
688 | switch (bus) { | 687 | switch (bus) { |
689 | case ACT2000_BUS_ISA: | 688 | case ACT2000_BUS_ISA: |
690 | for (i = 0; i < ISA_NRPORTS; i++) | 689 | for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++) |
691 | if (act2000_isa_detect(act2000_isa_ports[i])) { | 690 | if (act2000_isa_detect(act2000_isa_ports[i])) { |
692 | printk(KERN_INFO | 691 | printk(KERN_INFO "act2000: Detected " |
693 | "act2000: Detected ISA card at port 0x%x\n", | 692 | "ISA card at port 0x%x\n", |
694 | act2000_isa_ports[i]); | 693 | act2000_isa_ports[i]); |
695 | act2000_alloccard(bus, act2000_isa_ports[i], irq, id); | 694 | act2000_alloccard(bus, |
696 | } | 695 | act2000_isa_ports[i], irq, id); |
697 | break; | 696 | } |
698 | case ACT2000_BUS_MCA: | 697 | break; |
699 | case ACT2000_BUS_PCMCIA: | 698 | case ACT2000_BUS_MCA: |
700 | default: | 699 | case ACT2000_BUS_PCMCIA: |
701 | printk(KERN_WARNING | 700 | default: |
702 | "act2000: addcard: Invalid BUS type %d\n", | 701 | printk(KERN_WARNING |
703 | bus); | 702 | "act2000: addcard: Invalid BUS type %d\n", bus); |
704 | } | 703 | } |
705 | } | 704 | } |
706 | if (!cards) | 705 | if (!cards) |
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index ec5169604a6a..2d91049571a4 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -294,32 +294,33 @@ struct reply_t gigaset_tab_cid[] = | |||
294 | {RSP_OK, 604,604, -1, 605, 5, {ACT_CMD+AT_MSN}}, | 294 | {RSP_OK, 604,604, -1, 605, 5, {ACT_CMD+AT_MSN}}, |
295 | {RSP_OK, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, | 295 | {RSP_OK, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, |
296 | {RSP_NULL, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, | 296 | {RSP_NULL, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, |
297 | {RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"}, /* set "Endgeraetemodus" */ | 297 | {RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"}, |
298 | {RSP_OK, 607,607, -1, 608,-1}, | 298 | {RSP_OK, 607,607, -1, 608,-1}, |
299 | //{RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 608, 0, {ACT_ERROR}},//DELETE | ||
300 | {RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 609, 5, {ACT_CMD+AT_DIAL}}, | 299 | {RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 609, 5, {ACT_CMD+AT_DIAL}}, |
301 | {RSP_OK, 609,609, -1, 650, 0, {ACT_DIALING}}, | 300 | {RSP_OK, 609,609, -1, 650, 0, {ACT_DIALING}}, |
302 | 301 | ||
303 | {RSP_ZVLS, 608,608, 17, -1,-1, {ACT_DEBUG}}, | ||
304 | {RSP_ZCTP, 609,609, -1, -1,-1, {ACT_DEBUG}}, | ||
305 | {RSP_ZCPN, 609,609, -1, -1,-1, {ACT_DEBUG}}, | ||
306 | {RSP_ERROR, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, | 302 | {RSP_ERROR, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, |
307 | {EV_TIMEOUT, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, | 303 | {EV_TIMEOUT, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, |
308 | 304 | ||
309 | /* dialing */ | 305 | /* optional dialing responses */ |
310 | {RSP_ZCTP, 650,650, -1, -1,-1, {ACT_DEBUG}}, | 306 | {EV_BC_OPEN, 650,650, -1, 651,-1}, |
311 | {RSP_ZCPN, 650,650, -1, -1,-1, {ACT_DEBUG}}, | 307 | {RSP_ZVLS, 608,651, 17, -1,-1, {ACT_DEBUG}}, |
312 | {RSP_ZSAU, 650,650,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, /* some devices don't send this */ | 308 | {RSP_ZCTP, 609,651, -1, -1,-1, {ACT_DEBUG}}, |
313 | 309 | {RSP_ZCPN, 609,651, -1, -1,-1, {ACT_DEBUG}}, | |
314 | /* connection established */ | 310 | {RSP_ZSAU, 650,651,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, |
315 | {RSP_ZSAU, 650,650,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, //FIXME -> DLE1 | 311 | |
316 | {RSP_ZSAU, 750,750,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, //FIXME -> DLE1 | 312 | /* connect */ |
317 | 313 | {RSP_ZSAU, 650,650,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, | |
318 | {EV_BC_OPEN, 800,800, -1, 800,-1, {ACT_NOTIFY_BC_UP}}, //FIXME new constate + timeout | 314 | {RSP_ZSAU, 651,651,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT, |
315 | ACT_NOTIFY_BC_UP}}, | ||
316 | {RSP_ZSAU, 750,750,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, | ||
317 | {RSP_ZSAU, 751,751,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT, | ||
318 | ACT_NOTIFY_BC_UP}}, | ||
319 | {EV_BC_OPEN, 800,800, -1, 800,-1, {ACT_NOTIFY_BC_UP}}, | ||
319 | 320 | ||
320 | /* remote hangup */ | 321 | /* remote hangup */ |
321 | {RSP_ZSAU, 650,650,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT}}, | 322 | {RSP_ZSAU, 650,651,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT}}, |
322 | {RSP_ZSAU, 750,750,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, | 323 | {RSP_ZSAU, 750,751,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, |
323 | {RSP_ZSAU, 800,800,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, | 324 | {RSP_ZSAU, 800,800,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, |
324 | 325 | ||
325 | /* hangup */ | 326 | /* hangup */ |
@@ -358,7 +359,8 @@ struct reply_t gigaset_tab_cid[] = | |||
358 | {RSP_ZSAU, 700,729,ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT}}, | 359 | {RSP_ZSAU, 700,729,ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT}}, |
359 | {RSP_ZSAU, 700,729,ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT}}, | 360 | {RSP_ZSAU, 700,729,ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT}}, |
360 | 361 | ||
361 | {EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}}, | 362 | {EV_BC_OPEN, 750,750, -1, 751,-1}, |
363 | {EV_TIMEOUT, 750,751, -1, 0, 0, {ACT_CONNTIMEOUT}}, | ||
362 | 364 | ||
363 | /* B channel closed (general case) */ | 365 | /* B channel closed (general case) */ |
364 | {EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME | 366 | {EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME |
@@ -876,12 +878,6 @@ static void bchannel_down(struct bc_state *bcs) | |||
876 | 878 | ||
877 | static void bchannel_up(struct bc_state *bcs) | 879 | static void bchannel_up(struct bc_state *bcs) |
878 | { | 880 | { |
879 | if (!(bcs->chstate & CHS_D_UP)) { | ||
880 | dev_notice(bcs->cs->dev, "%s: D channel not up\n", __func__); | ||
881 | bcs->chstate |= CHS_D_UP; | ||
882 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); | ||
883 | } | ||
884 | |||
885 | if (bcs->chstate & CHS_B_UP) { | 881 | if (bcs->chstate & CHS_B_UP) { |
886 | dev_notice(bcs->cs->dev, "%s: B channel already up\n", | 882 | dev_notice(bcs->cs->dev, "%s: B channel already up\n", |
887 | __func__); | 883 | __func__); |
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index db3a1e4cd489..bed38fcc432b 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c | |||
@@ -174,12 +174,6 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) | |||
174 | pr_err("invalid size %d\n", size); | 174 | pr_err("invalid size %d\n", size); |
175 | return -EINVAL; | 175 | return -EINVAL; |
176 | } | 176 | } |
177 | src = iwb->read; | ||
178 | if (unlikely(limit >= BAS_OUTBUFSIZE + BAS_OUTBUFPAD || | ||
179 | (read < src && limit >= src))) { | ||
180 | pr_err("isoc write buffer frame reservation violated\n"); | ||
181 | return -EFAULT; | ||
182 | } | ||
183 | #endif | 177 | #endif |
184 | 178 | ||
185 | if (read < write) { | 179 | if (read < write) { |
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 31f91c18c698..27d5dd68f4fb 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c | |||
@@ -551,9 +551,7 @@ word api_put(APPL * appl, CAPI_MSG * msg) | |||
551 | dbug(1,dprintf("com=%x",msg->header.command)); | 551 | dbug(1,dprintf("com=%x",msg->header.command)); |
552 | 552 | ||
553 | for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0; | 553 | for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0; |
554 | for(i=0, ret = _BAD_MSG; | 554 | for(i=0, ret = _BAD_MSG; i < ARRAY_SIZE(ftable); i++) { |
555 | i<(sizeof(ftable)/sizeof(struct _ftable)); | ||
556 | i++) { | ||
557 | 555 | ||
558 | if(ftable[i].command==msg->header.command) { | 556 | if(ftable[i].command==msg->header.command) { |
559 | /* break loop if the message is correct, otherwise continue scan */ | 557 | /* break loop if the message is correct, otherwise continue scan */ |
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index c964b8d91ada..cb7616c5b60a 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c | |||
@@ -149,8 +149,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a) | |||
149 | diva_os_xdi_adapter_t *diva_current; | 149 | diva_os_xdi_adapter_t *diva_current; |
150 | diva_os_xdi_adapter_t *adapter_list[4]; | 150 | diva_os_xdi_adapter_t *adapter_list[4]; |
151 | PISDN_ADAPTER Slave; | 151 | PISDN_ADAPTER Slave; |
152 | unsigned long bar_length[sizeof(_4bri_bar_length) / | 152 | unsigned long bar_length[ARRAY_SIZE(_4bri_bar_length)]; |
153 | sizeof(_4bri_bar_length[0])]; | ||
154 | int v2 = _4bri_is_rev_2_card(a->CardOrdinal); | 153 | int v2 = _4bri_is_rev_2_card(a->CardOrdinal); |
155 | int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT; | 154 | int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT; |
156 | int factor = (tasks == 1) ? 1 : 2; | 155 | int factor = (tasks == 1) ? 1 : 2; |
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 3024566dd099..bde55d7287fa 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig | |||
@@ -39,3 +39,54 @@ config MISDN_HFCUSB | |||
39 | Enable support for USB ISDN TAs with Cologne Chip AG's | 39 | Enable support for USB ISDN TAs with Cologne Chip AG's |
40 | HFC-S USB ISDN Controller | 40 | HFC-S USB ISDN Controller |
41 | 41 | ||
42 | config MISDN_AVMFRITZ | ||
43 | tristate "Support for AVM FRITZ!CARD PCI" | ||
44 | depends on MISDN | ||
45 | depends on PCI | ||
46 | select MISDN_IPAC | ||
47 | help | ||
48 | Enable support for AVMs FRITZ!CARD PCI cards | ||
49 | |||
50 | config MISDN_SPEEDFAX | ||
51 | tristate "Support for Sedlbauer Speedfax+" | ||
52 | depends on MISDN | ||
53 | depends on PCI | ||
54 | select MISDN_IPAC | ||
55 | select MISDN_ISAR | ||
56 | help | ||
57 | Enable support for Sedlbauer Speedfax+. | ||
58 | |||
59 | config MISDN_INFINEON | ||
60 | tristate "Support for cards with Infineon chipset" | ||
61 | depends on MISDN | ||
62 | depends on PCI | ||
63 | select MISDN_IPAC | ||
64 | help | ||
65 | Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX | ||
66 | chip from Infineon (former manufacturer Siemens). | ||
67 | |||
68 | config MISDN_W6692 | ||
69 | tristate "Support for cards with Winbond 6692" | ||
70 | depends on MISDN | ||
71 | depends on PCI | ||
72 | help | ||
73 | Enable support for Winbond 6692 PCI chip based cards. | ||
74 | |||
75 | config MISDN_NETJET | ||
76 | tristate "Support for NETJet cards" | ||
77 | depends on MISDN | ||
78 | depends on PCI | ||
79 | select MISDN_IPAC | ||
80 | select ISDN_HDLC | ||
81 | help | ||
82 | Enable support for Traverse Technologies NETJet PCI cards. | ||
83 | |||
84 | |||
85 | config MISDN_IPAC | ||
86 | tristate | ||
87 | depends on MISDN | ||
88 | |||
89 | config MISDN_ISAR | ||
90 | tristate | ||
91 | depends on MISDN | ||
92 | |||
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index b0403526bbba..2987d990993f 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile | |||
@@ -6,3 +6,11 @@ | |||
6 | obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o | 6 | obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o |
7 | obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o | 7 | obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o |
8 | obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o | 8 | obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o |
9 | obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o | ||
10 | obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o | ||
11 | obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o | ||
12 | obj-$(CONFIG_MISDN_W6692) += w6692.o | ||
13 | obj-$(CONFIG_MISDN_NETJET) += netjet.o | ||
14 | # chip modules | ||
15 | obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o | ||
16 | obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o | ||
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c new file mode 100644 index 000000000000..81ac541d40d9 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/avmfritz.c | |||
@@ -0,0 +1,1152 @@ | |||
1 | /* | ||
2 | * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards | ||
3 | * Thanks to AVM, Berlin for informations | ||
4 | * | ||
5 | * Author Karsten Keil <keil@isdn4linux.de> | ||
6 | * | ||
7 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/mISDNhw.h> | ||
27 | #include <asm/unaligned.h> | ||
28 | #include "ipac.h" | ||
29 | |||
30 | |||
31 | #define AVMFRITZ_REV "2.1" | ||
32 | |||
33 | static int AVM_cnt; | ||
34 | static int debug; | ||
35 | |||
36 | enum { | ||
37 | AVM_FRITZ_PCI, | ||
38 | AVM_FRITZ_PCIV2, | ||
39 | }; | ||
40 | |||
41 | #define HDLC_FIFO 0x0 | ||
42 | #define HDLC_STATUS 0x4 | ||
43 | #define CHIP_WINDOW 0x10 | ||
44 | |||
45 | #define CHIP_INDEX 0x4 | ||
46 | #define AVM_HDLC_1 0x00 | ||
47 | #define AVM_HDLC_2 0x01 | ||
48 | #define AVM_ISAC_FIFO 0x02 | ||
49 | #define AVM_ISAC_REG_LOW 0x04 | ||
50 | #define AVM_ISAC_REG_HIGH 0x06 | ||
51 | |||
52 | #define AVM_STATUS0_IRQ_ISAC 0x01 | ||
53 | #define AVM_STATUS0_IRQ_HDLC 0x02 | ||
54 | #define AVM_STATUS0_IRQ_TIMER 0x04 | ||
55 | #define AVM_STATUS0_IRQ_MASK 0x07 | ||
56 | |||
57 | #define AVM_STATUS0_RESET 0x01 | ||
58 | #define AVM_STATUS0_DIS_TIMER 0x02 | ||
59 | #define AVM_STATUS0_RES_TIMER 0x04 | ||
60 | #define AVM_STATUS0_ENA_IRQ 0x08 | ||
61 | #define AVM_STATUS0_TESTBIT 0x10 | ||
62 | |||
63 | #define AVM_STATUS1_INT_SEL 0x0f | ||
64 | #define AVM_STATUS1_ENA_IOM 0x80 | ||
65 | |||
66 | #define HDLC_MODE_ITF_FLG 0x01 | ||
67 | #define HDLC_MODE_TRANS 0x02 | ||
68 | #define HDLC_MODE_CCR_7 0x04 | ||
69 | #define HDLC_MODE_CCR_16 0x08 | ||
70 | #define HDLC_MODE_TESTLOOP 0x80 | ||
71 | |||
72 | #define HDLC_INT_XPR 0x80 | ||
73 | #define HDLC_INT_XDU 0x40 | ||
74 | #define HDLC_INT_RPR 0x20 | ||
75 | #define HDLC_INT_MASK 0xE0 | ||
76 | |||
77 | #define HDLC_STAT_RME 0x01 | ||
78 | #define HDLC_STAT_RDO 0x10 | ||
79 | #define HDLC_STAT_CRCVFRRAB 0x0E | ||
80 | #define HDLC_STAT_CRCVFR 0x06 | ||
81 | #define HDLC_STAT_RML_MASK 0x3f00 | ||
82 | |||
83 | #define HDLC_CMD_XRS 0x80 | ||
84 | #define HDLC_CMD_XME 0x01 | ||
85 | #define HDLC_CMD_RRS 0x20 | ||
86 | #define HDLC_CMD_XML_MASK 0x3f00 | ||
87 | #define HDLC_FIFO_SIZE 32 | ||
88 | |||
89 | /* Fritz PCI v2.0 */ | ||
90 | |||
91 | #define AVM_HDLC_FIFO_1 0x10 | ||
92 | #define AVM_HDLC_FIFO_2 0x18 | ||
93 | |||
94 | #define AVM_HDLC_STATUS_1 0x14 | ||
95 | #define AVM_HDLC_STATUS_2 0x1c | ||
96 | |||
97 | #define AVM_ISACX_INDEX 0x04 | ||
98 | #define AVM_ISACX_DATA 0x08 | ||
99 | |||
100 | /* data struct */ | ||
101 | #define LOG_SIZE 63 | ||
102 | |||
103 | struct hdlc_stat_reg { | ||
104 | #ifdef __BIG_ENDIAN | ||
105 | u8 fill; | ||
106 | u8 mode; | ||
107 | u8 xml; | ||
108 | u8 cmd; | ||
109 | #else | ||
110 | u8 cmd; | ||
111 | u8 xml; | ||
112 | u8 mode; | ||
113 | u8 fill; | ||
114 | #endif | ||
115 | } __attribute__((packed)); | ||
116 | |||
117 | struct hdlc_hw { | ||
118 | union { | ||
119 | u32 ctrl; | ||
120 | struct hdlc_stat_reg sr; | ||
121 | } ctrl; | ||
122 | u32 stat; | ||
123 | }; | ||
124 | |||
125 | struct fritzcard { | ||
126 | struct list_head list; | ||
127 | struct pci_dev *pdev; | ||
128 | char name[MISDN_MAX_IDLEN]; | ||
129 | u8 type; | ||
130 | u8 ctrlreg; | ||
131 | u16 irq; | ||
132 | u32 irqcnt; | ||
133 | u32 addr; | ||
134 | spinlock_t lock; /* hw lock */ | ||
135 | struct isac_hw isac; | ||
136 | struct hdlc_hw hdlc[2]; | ||
137 | struct bchannel bch[2]; | ||
138 | char log[LOG_SIZE + 1]; | ||
139 | }; | ||
140 | |||
141 | static LIST_HEAD(Cards); | ||
142 | static DEFINE_RWLOCK(card_lock); /* protect Cards */ | ||
143 | |||
144 | static void | ||
145 | _set_debug(struct fritzcard *card) | ||
146 | { | ||
147 | card->isac.dch.debug = debug; | ||
148 | card->bch[0].debug = debug; | ||
149 | card->bch[1].debug = debug; | ||
150 | } | ||
151 | |||
152 | static int | ||
153 | set_debug(const char *val, struct kernel_param *kp) | ||
154 | { | ||
155 | int ret; | ||
156 | struct fritzcard *card; | ||
157 | |||
158 | ret = param_set_uint(val, kp); | ||
159 | if (!ret) { | ||
160 | read_lock(&card_lock); | ||
161 | list_for_each_entry(card, &Cards, list) | ||
162 | _set_debug(card); | ||
163 | read_unlock(&card_lock); | ||
164 | } | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | MODULE_AUTHOR("Karsten Keil"); | ||
169 | MODULE_LICENSE("GPL v2"); | ||
170 | MODULE_VERSION(AVMFRITZ_REV); | ||
171 | module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); | ||
172 | MODULE_PARM_DESC(debug, "avmfritz debug mask"); | ||
173 | |||
174 | /* Interface functions */ | ||
175 | |||
176 | static u8 | ||
177 | ReadISAC_V1(void *p, u8 offset) | ||
178 | { | ||
179 | struct fritzcard *fc = p; | ||
180 | u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; | ||
181 | |||
182 | outb(idx, fc->addr + CHIP_INDEX); | ||
183 | return inb(fc->addr + CHIP_WINDOW + (offset & 0xf)); | ||
184 | } | ||
185 | |||
186 | static void | ||
187 | WriteISAC_V1(void *p, u8 offset, u8 value) | ||
188 | { | ||
189 | struct fritzcard *fc = p; | ||
190 | u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; | ||
191 | |||
192 | outb(idx, fc->addr + CHIP_INDEX); | ||
193 | outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf)); | ||
194 | } | ||
195 | |||
196 | static void | ||
197 | ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size) | ||
198 | { | ||
199 | struct fritzcard *fc = p; | ||
200 | |||
201 | outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); | ||
202 | insb(fc->addr + CHIP_WINDOW, data, size); | ||
203 | } | ||
204 | |||
205 | static void | ||
206 | WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size) | ||
207 | { | ||
208 | struct fritzcard *fc = p; | ||
209 | |||
210 | outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); | ||
211 | outsb(fc->addr + CHIP_WINDOW, data, size); | ||
212 | } | ||
213 | |||
214 | static u8 | ||
215 | ReadISAC_V2(void *p, u8 offset) | ||
216 | { | ||
217 | struct fritzcard *fc = p; | ||
218 | |||
219 | outl(offset, fc->addr + AVM_ISACX_INDEX); | ||
220 | return 0xff & inl(fc->addr + AVM_ISACX_DATA); | ||
221 | } | ||
222 | |||
223 | static void | ||
224 | WriteISAC_V2(void *p, u8 offset, u8 value) | ||
225 | { | ||
226 | struct fritzcard *fc = p; | ||
227 | |||
228 | outl(offset, fc->addr + AVM_ISACX_INDEX); | ||
229 | outl(value, fc->addr + AVM_ISACX_DATA); | ||
230 | } | ||
231 | |||
232 | static void | ||
233 | ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size) | ||
234 | { | ||
235 | struct fritzcard *fc = p; | ||
236 | int i; | ||
237 | |||
238 | outl(off, fc->addr + AVM_ISACX_INDEX); | ||
239 | for (i = 0; i < size; i++) | ||
240 | data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA); | ||
241 | } | ||
242 | |||
243 | static void | ||
244 | WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size) | ||
245 | { | ||
246 | struct fritzcard *fc = p; | ||
247 | int i; | ||
248 | |||
249 | outl(off, fc->addr + AVM_ISACX_INDEX); | ||
250 | for (i = 0; i < size; i++) | ||
251 | outl(data[i], fc->addr + AVM_ISACX_DATA); | ||
252 | } | ||
253 | |||
254 | static struct bchannel * | ||
255 | Sel_BCS(struct fritzcard *fc, u32 channel) | ||
256 | { | ||
257 | if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && | ||
258 | (fc->bch[0].nr & channel)) | ||
259 | return &fc->bch[0]; | ||
260 | else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && | ||
261 | (fc->bch[1].nr & channel)) | ||
262 | return &fc->bch[1]; | ||
263 | else | ||
264 | return NULL; | ||
265 | } | ||
266 | |||
267 | static inline void | ||
268 | __write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { | ||
269 | u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1; | ||
270 | |||
271 | outl(idx, fc->addr + CHIP_INDEX); | ||
272 | outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS); | ||
273 | } | ||
274 | |||
275 | static inline void | ||
276 | __write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { | ||
277 | outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 : | ||
278 | AVM_HDLC_STATUS_1)); | ||
279 | } | ||
280 | |||
281 | void | ||
282 | write_ctrl(struct bchannel *bch, int which) { | ||
283 | struct fritzcard *fc = bch->hw; | ||
284 | struct hdlc_hw *hdlc; | ||
285 | |||
286 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | ||
287 | pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr, | ||
288 | which, hdlc->ctrl.ctrl); | ||
289 | switch (fc->type) { | ||
290 | case AVM_FRITZ_PCIV2: | ||
291 | __write_ctrl_pciv2(fc, hdlc, bch->nr); | ||
292 | break; | ||
293 | case AVM_FRITZ_PCI: | ||
294 | __write_ctrl_pci(fc, hdlc, bch->nr); | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | |||
300 | static inline u32 | ||
301 | __read_status_pci(u_long addr, u32 channel) | ||
302 | { | ||
303 | outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX); | ||
304 | return inl(addr + CHIP_WINDOW + HDLC_STATUS); | ||
305 | } | ||
306 | |||
307 | static inline u32 | ||
308 | __read_status_pciv2(u_long addr, u32 channel) | ||
309 | { | ||
310 | return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 : | ||
311 | AVM_HDLC_STATUS_1)); | ||
312 | } | ||
313 | |||
314 | |||
315 | static u32 | ||
316 | read_status(struct fritzcard *fc, u32 channel) | ||
317 | { | ||
318 | switch (fc->type) { | ||
319 | case AVM_FRITZ_PCIV2: | ||
320 | return __read_status_pciv2(fc->addr, channel); | ||
321 | case AVM_FRITZ_PCI: | ||
322 | return __read_status_pci(fc->addr, channel); | ||
323 | } | ||
324 | /* dummy */ | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static void | ||
329 | enable_hwirq(struct fritzcard *fc) | ||
330 | { | ||
331 | fc->ctrlreg |= AVM_STATUS0_ENA_IRQ; | ||
332 | outb(fc->ctrlreg, fc->addr + 2); | ||
333 | } | ||
334 | |||
335 | static void | ||
336 | disable_hwirq(struct fritzcard *fc) | ||
337 | { | ||
338 | fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ; | ||
339 | outb(fc->ctrlreg, fc->addr + 2); | ||
340 | } | ||
341 | |||
342 | static int | ||
343 | modehdlc(struct bchannel *bch, int protocol) | ||
344 | { | ||
345 | struct fritzcard *fc = bch->hw; | ||
346 | struct hdlc_hw *hdlc; | ||
347 | |||
348 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | ||
349 | pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, | ||
350 | '@' + bch->nr, bch->state, protocol, bch->nr); | ||
351 | hdlc->ctrl.ctrl = 0; | ||
352 | switch (protocol) { | ||
353 | case -1: /* used for init */ | ||
354 | bch->state = -1; | ||
355 | case ISDN_P_NONE: | ||
356 | if (bch->state == ISDN_P_NONE) | ||
357 | break; | ||
358 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; | ||
359 | hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; | ||
360 | write_ctrl(bch, 5); | ||
361 | bch->state = ISDN_P_NONE; | ||
362 | test_and_clear_bit(FLG_HDLC, &bch->Flags); | ||
363 | test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); | ||
364 | break; | ||
365 | case ISDN_P_B_RAW: | ||
366 | bch->state = protocol; | ||
367 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; | ||
368 | hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; | ||
369 | write_ctrl(bch, 5); | ||
370 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; | ||
371 | write_ctrl(bch, 1); | ||
372 | hdlc->ctrl.sr.cmd = 0; | ||
373 | test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); | ||
374 | break; | ||
375 | case ISDN_P_B_HDLC: | ||
376 | bch->state = protocol; | ||
377 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; | ||
378 | hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG; | ||
379 | write_ctrl(bch, 5); | ||
380 | hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; | ||
381 | write_ctrl(bch, 1); | ||
382 | hdlc->ctrl.sr.cmd = 0; | ||
383 | test_and_set_bit(FLG_HDLC, &bch->Flags); | ||
384 | break; | ||
385 | default: | ||
386 | pr_info("%s: protocol not known %x\n", fc->name, protocol); | ||
387 | return -ENOPROTOOPT; | ||
388 | } | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static void | ||
393 | hdlc_empty_fifo(struct bchannel *bch, int count) | ||
394 | { | ||
395 | u32 *ptr; | ||
396 | u8 *p; | ||
397 | u32 val, addr; | ||
398 | int cnt = 0; | ||
399 | struct fritzcard *fc = bch->hw; | ||
400 | |||
401 | pr_debug("%s: %s %d\n", fc->name, __func__, count); | ||
402 | if (!bch->rx_skb) { | ||
403 | bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); | ||
404 | if (!bch->rx_skb) { | ||
405 | pr_info("%s: B receive out of memory\n", | ||
406 | fc->name); | ||
407 | return; | ||
408 | } | ||
409 | } | ||
410 | if ((bch->rx_skb->len + count) > bch->maxlen) { | ||
411 | pr_debug("%s: overrun %d\n", fc->name, | ||
412 | bch->rx_skb->len + count); | ||
413 | return; | ||
414 | } | ||
415 | p = skb_put(bch->rx_skb, count); | ||
416 | ptr = (u32 *)p; | ||
417 | if (AVM_FRITZ_PCIV2 == fc->type) | ||
418 | addr = fc->addr + (bch->nr == 2 ? | ||
419 | AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); | ||
420 | else { | ||
421 | addr = fc->addr + CHIP_WINDOW; | ||
422 | outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); | ||
423 | } | ||
424 | while (cnt < count) { | ||
425 | val = le32_to_cpu(inl(addr)); | ||
426 | put_unaligned(val, ptr); | ||
427 | ptr++; | ||
428 | cnt += 4; | ||
429 | } | ||
430 | if (debug & DEBUG_HW_BFIFO) { | ||
431 | snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", | ||
432 | bch->nr, fc->name, count); | ||
433 | print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); | ||
434 | } | ||
435 | } | ||
436 | |||
437 | static void | ||
438 | hdlc_fill_fifo(struct bchannel *bch) | ||
439 | { | ||
440 | struct fritzcard *fc = bch->hw; | ||
441 | struct hdlc_hw *hdlc; | ||
442 | int count, cnt = 0; | ||
443 | u8 *p; | ||
444 | u32 *ptr, val, addr; | ||
445 | |||
446 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | ||
447 | if (!bch->tx_skb) | ||
448 | return; | ||
449 | count = bch->tx_skb->len - bch->tx_idx; | ||
450 | if (count <= 0) | ||
451 | return; | ||
452 | p = bch->tx_skb->data + bch->tx_idx; | ||
453 | hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; | ||
454 | if (count > HDLC_FIFO_SIZE) { | ||
455 | count = HDLC_FIFO_SIZE; | ||
456 | } else { | ||
457 | if (test_bit(FLG_HDLC, &bch->Flags)) | ||
458 | hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; | ||
459 | } | ||
460 | pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, | ||
461 | bch->tx_idx, bch->tx_skb->len); | ||
462 | ptr = (u32 *)p; | ||
463 | bch->tx_idx += count; | ||
464 | hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count); | ||
465 | if (AVM_FRITZ_PCIV2 == fc->type) { | ||
466 | __write_ctrl_pciv2(fc, hdlc, bch->nr); | ||
467 | addr = fc->addr + (bch->nr == 2 ? | ||
468 | AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); | ||
469 | } else { | ||
470 | __write_ctrl_pci(fc, hdlc, bch->nr); | ||
471 | addr = fc->addr + CHIP_WINDOW; | ||
472 | } | ||
473 | while (cnt < count) { | ||
474 | val = get_unaligned(ptr); | ||
475 | outl(cpu_to_le32(val), addr); | ||
476 | ptr++; | ||
477 | cnt += 4; | ||
478 | } | ||
479 | if (debug & DEBUG_HW_BFIFO) { | ||
480 | snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", | ||
481 | bch->nr, fc->name, count); | ||
482 | print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | static void | ||
487 | HDLC_irq_xpr(struct bchannel *bch) | ||
488 | { | ||
489 | if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) | ||
490 | hdlc_fill_fifo(bch); | ||
491 | else { | ||
492 | if (bch->tx_skb) { | ||
493 | /* send confirm, on trans, free on hdlc. */ | ||
494 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
495 | confirm_Bsend(bch); | ||
496 | dev_kfree_skb(bch->tx_skb); | ||
497 | } | ||
498 | if (get_next_bframe(bch)) | ||
499 | hdlc_fill_fifo(bch); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | static void | ||
504 | HDLC_irq(struct bchannel *bch, u32 stat) | ||
505 | { | ||
506 | struct fritzcard *fc = bch->hw; | ||
507 | int len; | ||
508 | struct hdlc_hw *hdlc; | ||
509 | |||
510 | hdlc = &fc->hdlc[(bch->nr - 1) & 1]; | ||
511 | pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); | ||
512 | if (stat & HDLC_INT_RPR) { | ||
513 | if (stat & HDLC_STAT_RDO) { | ||
514 | hdlc->ctrl.sr.xml = 0; | ||
515 | hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; | ||
516 | write_ctrl(bch, 1); | ||
517 | hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS; | ||
518 | write_ctrl(bch, 1); | ||
519 | if (bch->rx_skb) | ||
520 | skb_trim(bch->rx_skb, 0); | ||
521 | } else { | ||
522 | len = (stat & HDLC_STAT_RML_MASK) >> 8; | ||
523 | if (!len) | ||
524 | len = 32; | ||
525 | hdlc_empty_fifo(bch, len); | ||
526 | if (!bch->rx_skb) | ||
527 | goto handle_tx; | ||
528 | if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, | ||
529 | &bch->Flags)) { | ||
530 | if (((stat & HDLC_STAT_CRCVFRRAB) == | ||
531 | HDLC_STAT_CRCVFR) || | ||
532 | test_bit(FLG_TRANSPARENT, &bch->Flags)) { | ||
533 | recv_Bchannel(bch, 0); | ||
534 | } else { | ||
535 | pr_debug("%s: got invalid frame\n", | ||
536 | fc->name); | ||
537 | skb_trim(bch->rx_skb, 0); | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | } | ||
542 | handle_tx: | ||
543 | if (stat & HDLC_INT_XDU) { | ||
544 | /* Here we lost an TX interrupt, so | ||
545 | * restart transmitting the whole frame on HDLC | ||
546 | * in transparent mode we send the next data | ||
547 | */ | ||
548 | if (bch->tx_skb) | ||
549 | pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n", | ||
550 | fc->name, bch->nr, bch->tx_skb->len, | ||
551 | bch->tx_idx, bch->Flags); | ||
552 | else | ||
553 | pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n", | ||
554 | fc->name, bch->nr, bch->Flags); | ||
555 | if (bch->tx_skb && bch->tx_skb->len) { | ||
556 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
557 | bch->tx_idx = 0; | ||
558 | } | ||
559 | hdlc->ctrl.sr.xml = 0; | ||
560 | hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; | ||
561 | write_ctrl(bch, 1); | ||
562 | hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS; | ||
563 | HDLC_irq_xpr(bch); | ||
564 | return; | ||
565 | } else if (stat & HDLC_INT_XPR) | ||
566 | HDLC_irq_xpr(bch); | ||
567 | } | ||
568 | |||
569 | static inline void | ||
570 | HDLC_irq_main(struct fritzcard *fc) | ||
571 | { | ||
572 | u32 stat; | ||
573 | struct bchannel *bch; | ||
574 | |||
575 | stat = read_status(fc, 1); | ||
576 | if (stat & HDLC_INT_MASK) { | ||
577 | bch = Sel_BCS(fc, 1); | ||
578 | if (bch) | ||
579 | HDLC_irq(bch, stat); | ||
580 | else | ||
581 | pr_debug("%s: spurious ch1 IRQ\n", fc->name); | ||
582 | } | ||
583 | stat = read_status(fc, 2); | ||
584 | if (stat & HDLC_INT_MASK) { | ||
585 | bch = Sel_BCS(fc, 2); | ||
586 | if (bch) | ||
587 | HDLC_irq(bch, stat); | ||
588 | else | ||
589 | pr_debug("%s: spurious ch2 IRQ\n", fc->name); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | static irqreturn_t | ||
594 | avm_fritz_interrupt(int intno, void *dev_id) | ||
595 | { | ||
596 | struct fritzcard *fc = dev_id; | ||
597 | u8 val; | ||
598 | u8 sval; | ||
599 | |||
600 | spin_lock(&fc->lock); | ||
601 | sval = inb(fc->addr + 2); | ||
602 | pr_debug("%s: irq stat0 %x\n", fc->name, sval); | ||
603 | if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { | ||
604 | /* shared IRQ from other HW */ | ||
605 | spin_unlock(&fc->lock); | ||
606 | return IRQ_NONE; | ||
607 | } | ||
608 | fc->irqcnt++; | ||
609 | |||
610 | if (!(sval & AVM_STATUS0_IRQ_ISAC)) { | ||
611 | val = ReadISAC_V1(fc, ISAC_ISTA); | ||
612 | mISDNisac_irq(&fc->isac, val); | ||
613 | } | ||
614 | if (!(sval & AVM_STATUS0_IRQ_HDLC)) | ||
615 | HDLC_irq_main(fc); | ||
616 | spin_unlock(&fc->lock); | ||
617 | return IRQ_HANDLED; | ||
618 | } | ||
619 | |||
620 | static irqreturn_t | ||
621 | avm_fritzv2_interrupt(int intno, void *dev_id) | ||
622 | { | ||
623 | struct fritzcard *fc = dev_id; | ||
624 | u8 val; | ||
625 | u8 sval; | ||
626 | |||
627 | spin_lock(&fc->lock); | ||
628 | sval = inb(fc->addr + 2); | ||
629 | pr_debug("%s: irq stat0 %x\n", fc->name, sval); | ||
630 | if (!(sval & AVM_STATUS0_IRQ_MASK)) { | ||
631 | /* shared IRQ from other HW */ | ||
632 | spin_unlock(&fc->lock); | ||
633 | return IRQ_NONE; | ||
634 | } | ||
635 | fc->irqcnt++; | ||
636 | |||
637 | if (sval & AVM_STATUS0_IRQ_HDLC) | ||
638 | HDLC_irq_main(fc); | ||
639 | if (sval & AVM_STATUS0_IRQ_ISAC) { | ||
640 | val = ReadISAC_V2(fc, ISACX_ISTA); | ||
641 | mISDNisac_irq(&fc->isac, val); | ||
642 | } | ||
643 | if (sval & AVM_STATUS0_IRQ_TIMER) { | ||
644 | pr_debug("%s: timer irq\n", fc->name); | ||
645 | outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2); | ||
646 | udelay(1); | ||
647 | outb(fc->ctrlreg, fc->addr + 2); | ||
648 | } | ||
649 | spin_unlock(&fc->lock); | ||
650 | return IRQ_HANDLED; | ||
651 | } | ||
652 | |||
653 | static int | ||
654 | avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) | ||
655 | { | ||
656 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
657 | struct fritzcard *fc = bch->hw; | ||
658 | int ret = -EINVAL; | ||
659 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
660 | u32 id; | ||
661 | u_long flags; | ||
662 | |||
663 | switch (hh->prim) { | ||
664 | case PH_DATA_REQ: | ||
665 | spin_lock_irqsave(&fc->lock, flags); | ||
666 | ret = bchannel_senddata(bch, skb); | ||
667 | if (ret > 0) { /* direct TX */ | ||
668 | id = hh->id; /* skb can be freed */ | ||
669 | hdlc_fill_fifo(bch); | ||
670 | ret = 0; | ||
671 | spin_unlock_irqrestore(&fc->lock, flags); | ||
672 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
673 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
674 | } else | ||
675 | spin_unlock_irqrestore(&fc->lock, flags); | ||
676 | return ret; | ||
677 | case PH_ACTIVATE_REQ: | ||
678 | spin_lock_irqsave(&fc->lock, flags); | ||
679 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
680 | ret = modehdlc(bch, ch->protocol); | ||
681 | else | ||
682 | ret = 0; | ||
683 | spin_unlock_irqrestore(&fc->lock, flags); | ||
684 | if (!ret) | ||
685 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
686 | NULL, GFP_KERNEL); | ||
687 | break; | ||
688 | case PH_DEACTIVATE_REQ: | ||
689 | spin_lock_irqsave(&fc->lock, flags); | ||
690 | mISDN_clear_bchannel(bch); | ||
691 | modehdlc(bch, ISDN_P_NONE); | ||
692 | spin_unlock_irqrestore(&fc->lock, flags); | ||
693 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
694 | NULL, GFP_KERNEL); | ||
695 | ret = 0; | ||
696 | break; | ||
697 | } | ||
698 | if (!ret) | ||
699 | dev_kfree_skb(skb); | ||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | static void | ||
704 | inithdlc(struct fritzcard *fc) | ||
705 | { | ||
706 | modehdlc(&fc->bch[0], -1); | ||
707 | modehdlc(&fc->bch[1], -1); | ||
708 | } | ||
709 | |||
710 | void | ||
711 | clear_pending_hdlc_ints(struct fritzcard *fc) | ||
712 | { | ||
713 | u32 val; | ||
714 | |||
715 | val = read_status(fc, 1); | ||
716 | pr_debug("%s: HDLC 1 STA %x\n", fc->name, val); | ||
717 | val = read_status(fc, 2); | ||
718 | pr_debug("%s: HDLC 2 STA %x\n", fc->name, val); | ||
719 | } | ||
720 | |||
721 | static void | ||
722 | reset_avm(struct fritzcard *fc) | ||
723 | { | ||
724 | switch (fc->type) { | ||
725 | case AVM_FRITZ_PCI: | ||
726 | fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER; | ||
727 | break; | ||
728 | case AVM_FRITZ_PCIV2: | ||
729 | fc->ctrlreg = AVM_STATUS0_RESET; | ||
730 | break; | ||
731 | } | ||
732 | if (debug & DEBUG_HW) | ||
733 | pr_notice("%s: reset\n", fc->name); | ||
734 | disable_hwirq(fc); | ||
735 | mdelay(5); | ||
736 | switch (fc->type) { | ||
737 | case AVM_FRITZ_PCI: | ||
738 | fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER; | ||
739 | disable_hwirq(fc); | ||
740 | outb(AVM_STATUS1_ENA_IOM, fc->addr + 3); | ||
741 | break; | ||
742 | case AVM_FRITZ_PCIV2: | ||
743 | fc->ctrlreg = 0; | ||
744 | disable_hwirq(fc); | ||
745 | break; | ||
746 | } | ||
747 | mdelay(1); | ||
748 | if (debug & DEBUG_HW) | ||
749 | pr_notice("%s: S0/S1 %x/%x\n", fc->name, | ||
750 | inb(fc->addr + 2), inb(fc->addr + 3)); | ||
751 | } | ||
752 | |||
753 | static int | ||
754 | init_card(struct fritzcard *fc) | ||
755 | { | ||
756 | int ret, cnt = 3; | ||
757 | u_long flags; | ||
758 | |||
759 | reset_avm(fc); /* disable IRQ */ | ||
760 | if (fc->type == AVM_FRITZ_PCIV2) | ||
761 | ret = request_irq(fc->irq, avm_fritzv2_interrupt, | ||
762 | IRQF_SHARED, fc->name, fc); | ||
763 | else | ||
764 | ret = request_irq(fc->irq, avm_fritz_interrupt, | ||
765 | IRQF_SHARED, fc->name, fc); | ||
766 | if (ret) { | ||
767 | pr_info("%s: couldn't get interrupt %d\n", | ||
768 | fc->name, fc->irq); | ||
769 | return ret; | ||
770 | } | ||
771 | while (cnt--) { | ||
772 | spin_lock_irqsave(&fc->lock, flags); | ||
773 | ret = fc->isac.init(&fc->isac); | ||
774 | if (ret) { | ||
775 | spin_unlock_irqrestore(&fc->lock, flags); | ||
776 | pr_info("%s: ISAC init failed with %d\n", | ||
777 | fc->name, ret); | ||
778 | break; | ||
779 | } | ||
780 | clear_pending_hdlc_ints(fc); | ||
781 | inithdlc(fc); | ||
782 | enable_hwirq(fc); | ||
783 | /* RESET Receiver and Transmitter */ | ||
784 | if (AVM_FRITZ_PCIV2 == fc->type) { | ||
785 | WriteISAC_V2(fc, ISACX_MASK, 0); | ||
786 | WriteISAC_V2(fc, ISACX_CMDRD, 0x41); | ||
787 | } else { | ||
788 | WriteISAC_V1(fc, ISAC_MASK, 0); | ||
789 | WriteISAC_V1(fc, ISAC_CMDR, 0x41); | ||
790 | } | ||
791 | spin_unlock_irqrestore(&fc->lock, flags); | ||
792 | /* Timeout 10ms */ | ||
793 | msleep_interruptible(10); | ||
794 | if (debug & DEBUG_HW) | ||
795 | pr_notice("%s: IRQ %d count %d\n", fc->name, | ||
796 | fc->irq, fc->irqcnt); | ||
797 | if (!fc->irqcnt) { | ||
798 | pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", | ||
799 | fc->name, fc->irq, 3 - cnt); | ||
800 | reset_avm(fc); | ||
801 | } else | ||
802 | return 0; | ||
803 | } | ||
804 | free_irq(fc->irq, fc); | ||
805 | return -EIO; | ||
806 | } | ||
807 | |||
808 | static int | ||
809 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
810 | { | ||
811 | int ret = 0; | ||
812 | struct fritzcard *fc = bch->hw; | ||
813 | |||
814 | switch (cq->op) { | ||
815 | case MISDN_CTRL_GETOP: | ||
816 | cq->op = 0; | ||
817 | break; | ||
818 | /* Nothing implemented yet */ | ||
819 | case MISDN_CTRL_FILL_EMPTY: | ||
820 | default: | ||
821 | pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); | ||
822 | ret = -EINVAL; | ||
823 | break; | ||
824 | } | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | static int | ||
829 | avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
830 | { | ||
831 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
832 | struct fritzcard *fc = bch->hw; | ||
833 | int ret = -EINVAL; | ||
834 | u_long flags; | ||
835 | |||
836 | pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); | ||
837 | switch (cmd) { | ||
838 | case CLOSE_CHANNEL: | ||
839 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
840 | if (test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
841 | spin_lock_irqsave(&fc->lock, flags); | ||
842 | mISDN_freebchannel(bch); | ||
843 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
844 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
845 | modehdlc(bch, ISDN_P_NONE); | ||
846 | spin_unlock_irqrestore(&fc->lock, flags); | ||
847 | } | ||
848 | ch->protocol = ISDN_P_NONE; | ||
849 | ch->peer = NULL; | ||
850 | module_put(THIS_MODULE); | ||
851 | ret = 0; | ||
852 | break; | ||
853 | case CONTROL_CHANNEL: | ||
854 | ret = channel_bctrl(bch, arg); | ||
855 | break; | ||
856 | default: | ||
857 | pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd); | ||
858 | } | ||
859 | return ret; | ||
860 | } | ||
861 | |||
862 | static int | ||
863 | channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) | ||
864 | { | ||
865 | int ret = 0; | ||
866 | |||
867 | switch (cq->op) { | ||
868 | case MISDN_CTRL_GETOP: | ||
869 | cq->op = MISDN_CTRL_LOOP; | ||
870 | break; | ||
871 | case MISDN_CTRL_LOOP: | ||
872 | /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ | ||
873 | if (cq->channel < 0 || cq->channel > 3) { | ||
874 | ret = -EINVAL; | ||
875 | break; | ||
876 | } | ||
877 | ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); | ||
878 | break; | ||
879 | default: | ||
880 | pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); | ||
881 | ret = -EINVAL; | ||
882 | break; | ||
883 | } | ||
884 | return ret; | ||
885 | } | ||
886 | |||
887 | static int | ||
888 | open_bchannel(struct fritzcard *fc, struct channel_req *rq) | ||
889 | { | ||
890 | struct bchannel *bch; | ||
891 | |||
892 | if (rq->adr.channel > 2) | ||
893 | return -EINVAL; | ||
894 | if (rq->protocol == ISDN_P_NONE) | ||
895 | return -EINVAL; | ||
896 | bch = &fc->bch[rq->adr.channel - 1]; | ||
897 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
898 | return -EBUSY; /* b-channel can be only open once */ | ||
899 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | ||
900 | bch->ch.protocol = rq->protocol; | ||
901 | rq->ch = &bch->ch; | ||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | /* | ||
906 | * device control function | ||
907 | */ | ||
908 | static int | ||
909 | avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
910 | { | ||
911 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
912 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
913 | struct fritzcard *fc = dch->hw; | ||
914 | struct channel_req *rq; | ||
915 | int err = 0; | ||
916 | |||
917 | pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); | ||
918 | switch (cmd) { | ||
919 | case OPEN_CHANNEL: | ||
920 | rq = arg; | ||
921 | if (rq->protocol == ISDN_P_TE_S0) | ||
922 | err = fc->isac.open(&fc->isac, rq); | ||
923 | else | ||
924 | err = open_bchannel(fc, rq); | ||
925 | if (err) | ||
926 | break; | ||
927 | if (!try_module_get(THIS_MODULE)) | ||
928 | pr_info("%s: cannot get module\n", fc->name); | ||
929 | break; | ||
930 | case CLOSE_CHANNEL: | ||
931 | pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id, | ||
932 | __builtin_return_address(0)); | ||
933 | module_put(THIS_MODULE); | ||
934 | break; | ||
935 | case CONTROL_CHANNEL: | ||
936 | err = channel_ctrl(fc, arg); | ||
937 | break; | ||
938 | default: | ||
939 | pr_debug("%s: %s unknown command %x\n", | ||
940 | fc->name, __func__, cmd); | ||
941 | return -EINVAL; | ||
942 | } | ||
943 | return err; | ||
944 | } | ||
945 | |||
946 | int | ||
947 | setup_fritz(struct fritzcard *fc) | ||
948 | { | ||
949 | u32 val, ver; | ||
950 | |||
951 | if (!request_region(fc->addr, 32, fc->name)) { | ||
952 | pr_info("%s: AVM config port %x-%x already in use\n", | ||
953 | fc->name, fc->addr, fc->addr + 31); | ||
954 | return -EIO; | ||
955 | } | ||
956 | switch (fc->type) { | ||
957 | case AVM_FRITZ_PCI: | ||
958 | val = inl(fc->addr); | ||
959 | outl(AVM_HDLC_1, fc->addr + CHIP_INDEX); | ||
960 | ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24; | ||
961 | if (debug & DEBUG_HW) { | ||
962 | pr_notice("%s: PCI stat %#x\n", fc->name, val); | ||
963 | pr_notice("%s: PCI Class %X Rev %d\n", fc->name, | ||
964 | val & 0xff, (val >> 8) & 0xff); | ||
965 | pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); | ||
966 | } | ||
967 | ASSIGN_FUNC(V1, ISAC, fc->isac); | ||
968 | fc->isac.type = IPAC_TYPE_ISAC; | ||
969 | break; | ||
970 | case AVM_FRITZ_PCIV2: | ||
971 | val = inl(fc->addr); | ||
972 | ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24; | ||
973 | if (debug & DEBUG_HW) { | ||
974 | pr_notice("%s: PCI V2 stat %#x\n", fc->name, val); | ||
975 | pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name, | ||
976 | val & 0xff, (val>>8) & 0xff); | ||
977 | pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); | ||
978 | } | ||
979 | ASSIGN_FUNC(V2, ISAC, fc->isac); | ||
980 | fc->isac.type = IPAC_TYPE_ISACX; | ||
981 | break; | ||
982 | default: | ||
983 | release_region(fc->addr, 32); | ||
984 | pr_info("%s: AVM unknown type %d\n", fc->name, fc->type); | ||
985 | return -ENODEV; | ||
986 | } | ||
987 | pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name, | ||
988 | (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" : | ||
989 | "AVM Fritz!CARD PCIv2", fc->irq, fc->addr); | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static void | ||
994 | release_card(struct fritzcard *card) | ||
995 | { | ||
996 | u_long flags; | ||
997 | |||
998 | disable_hwirq(card); | ||
999 | spin_lock_irqsave(&card->lock, flags); | ||
1000 | modehdlc(&card->bch[0], ISDN_P_NONE); | ||
1001 | modehdlc(&card->bch[1], ISDN_P_NONE); | ||
1002 | spin_unlock_irqrestore(&card->lock, flags); | ||
1003 | card->isac.release(&card->isac); | ||
1004 | free_irq(card->irq, card); | ||
1005 | mISDN_freebchannel(&card->bch[1]); | ||
1006 | mISDN_freebchannel(&card->bch[0]); | ||
1007 | mISDN_unregister_device(&card->isac.dch.dev); | ||
1008 | release_region(card->addr, 32); | ||
1009 | pci_disable_device(card->pdev); | ||
1010 | pci_set_drvdata(card->pdev, NULL); | ||
1011 | write_lock_irqsave(&card_lock, flags); | ||
1012 | list_del(&card->list); | ||
1013 | write_unlock_irqrestore(&card_lock, flags); | ||
1014 | kfree(card); | ||
1015 | AVM_cnt--; | ||
1016 | } | ||
1017 | |||
1018 | static int __devinit | ||
1019 | setup_instance(struct fritzcard *card) | ||
1020 | { | ||
1021 | int i, err; | ||
1022 | u_long flags; | ||
1023 | |||
1024 | snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); | ||
1025 | write_lock_irqsave(&card_lock, flags); | ||
1026 | list_add_tail(&card->list, &Cards); | ||
1027 | write_unlock_irqrestore(&card_lock, flags); | ||
1028 | |||
1029 | _set_debug(card); | ||
1030 | card->isac.name = card->name; | ||
1031 | spin_lock_init(&card->lock); | ||
1032 | card->isac.hwlock = &card->lock; | ||
1033 | mISDNisac_init(&card->isac, card); | ||
1034 | |||
1035 | card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1036 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
1037 | card->isac.dch.dev.D.ctrl = avm_dctrl; | ||
1038 | for (i = 0; i < 2; i++) { | ||
1039 | card->bch[i].nr = i + 1; | ||
1040 | set_channelmap(i + 1, card->isac.dch.dev.channelmap); | ||
1041 | mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); | ||
1042 | card->bch[i].hw = card; | ||
1043 | card->bch[i].ch.send = avm_l2l1B; | ||
1044 | card->bch[i].ch.ctrl = avm_bctrl; | ||
1045 | card->bch[i].ch.nr = i + 1; | ||
1046 | list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels); | ||
1047 | } | ||
1048 | err = setup_fritz(card); | ||
1049 | if (err) | ||
1050 | goto error; | ||
1051 | err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, | ||
1052 | card->name); | ||
1053 | if (err) | ||
1054 | goto error_reg; | ||
1055 | err = init_card(card); | ||
1056 | if (!err) { | ||
1057 | AVM_cnt++; | ||
1058 | pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt); | ||
1059 | return 0; | ||
1060 | } | ||
1061 | mISDN_unregister_device(&card->isac.dch.dev); | ||
1062 | error_reg: | ||
1063 | release_region(card->addr, 32); | ||
1064 | error: | ||
1065 | card->isac.release(&card->isac); | ||
1066 | mISDN_freebchannel(&card->bch[1]); | ||
1067 | mISDN_freebchannel(&card->bch[0]); | ||
1068 | write_lock_irqsave(&card_lock, flags); | ||
1069 | list_del(&card->list); | ||
1070 | write_unlock_irqrestore(&card_lock, flags); | ||
1071 | kfree(card); | ||
1072 | return err; | ||
1073 | } | ||
1074 | |||
1075 | static int __devinit | ||
1076 | fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
1077 | { | ||
1078 | int err = -ENOMEM; | ||
1079 | struct fritzcard *card; | ||
1080 | |||
1081 | card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL); | ||
1082 | if (!card) { | ||
1083 | pr_info("No kmem for fritzcard\n"); | ||
1084 | return err; | ||
1085 | } | ||
1086 | if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) | ||
1087 | card->type = AVM_FRITZ_PCIV2; | ||
1088 | else | ||
1089 | card->type = AVM_FRITZ_PCI; | ||
1090 | card->pdev = pdev; | ||
1091 | err = pci_enable_device(pdev); | ||
1092 | if (err) { | ||
1093 | kfree(card); | ||
1094 | return err; | ||
1095 | } | ||
1096 | |||
1097 | pr_notice("mISDN: found adapter %s at %s\n", | ||
1098 | (char *) ent->driver_data, pci_name(pdev)); | ||
1099 | |||
1100 | card->addr = pci_resource_start(pdev, 1); | ||
1101 | card->irq = pdev->irq; | ||
1102 | pci_set_drvdata(pdev, card); | ||
1103 | err = setup_instance(card); | ||
1104 | if (err) | ||
1105 | pci_set_drvdata(pdev, NULL); | ||
1106 | return err; | ||
1107 | } | ||
1108 | |||
1109 | static void __devexit | ||
1110 | fritz_remove_pci(struct pci_dev *pdev) | ||
1111 | { | ||
1112 | struct fritzcard *card = pci_get_drvdata(pdev); | ||
1113 | |||
1114 | if (card) | ||
1115 | release_card(card); | ||
1116 | else | ||
1117 | if (debug) | ||
1118 | pr_info("%s: drvdata allready removed\n", __func__); | ||
1119 | } | ||
1120 | |||
1121 | static struct pci_device_id fcpci_ids[] __devinitdata = { | ||
1122 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID, | ||
1123 | 0, 0, (unsigned long) "Fritz!Card PCI"}, | ||
1124 | { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID, | ||
1125 | 0, 0, (unsigned long) "Fritz!Card PCI v2" }, | ||
1126 | { } | ||
1127 | }; | ||
1128 | MODULE_DEVICE_TABLE(pci, fcpci_ids); | ||
1129 | |||
1130 | static struct pci_driver fcpci_driver = { | ||
1131 | .name = "fcpci", | ||
1132 | .probe = fritzpci_probe, | ||
1133 | .remove = __devexit_p(fritz_remove_pci), | ||
1134 | .id_table = fcpci_ids, | ||
1135 | }; | ||
1136 | |||
1137 | static int __init AVM_init(void) | ||
1138 | { | ||
1139 | int err; | ||
1140 | |||
1141 | pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV); | ||
1142 | err = pci_register_driver(&fcpci_driver); | ||
1143 | return err; | ||
1144 | } | ||
1145 | |||
1146 | static void __exit AVM_cleanup(void) | ||
1147 | { | ||
1148 | pci_unregister_driver(&fcpci_driver); | ||
1149 | } | ||
1150 | |||
1151 | module_init(AVM_init); | ||
1152 | module_exit(AVM_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index e1dab30aed30..faed794cf75a 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
@@ -3416,22 +3416,8 @@ deactivate_bchannel(struct bchannel *bch) | |||
3416 | u_long flags; | 3416 | u_long flags; |
3417 | 3417 | ||
3418 | spin_lock_irqsave(&hc->lock, flags); | 3418 | spin_lock_irqsave(&hc->lock, flags); |
3419 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | 3419 | mISDN_clear_bchannel(bch); |
3420 | dev_kfree_skb(bch->next_skb); | ||
3421 | bch->next_skb = NULL; | ||
3422 | } | ||
3423 | if (bch->tx_skb) { | ||
3424 | dev_kfree_skb(bch->tx_skb); | ||
3425 | bch->tx_skb = NULL; | ||
3426 | } | ||
3427 | bch->tx_idx = 0; | ||
3428 | if (bch->rx_skb) { | ||
3429 | dev_kfree_skb(bch->rx_skb); | ||
3430 | bch->rx_skb = NULL; | ||
3431 | } | ||
3432 | hc->chan[bch->slot].coeff_count = 0; | 3420 | hc->chan[bch->slot].coeff_count = 0; |
3433 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
3434 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
3435 | hc->chan[bch->slot].rx_off = 0; | 3421 | hc->chan[bch->slot].rx_off = 0; |
3436 | hc->chan[bch->slot].conf = -1; | 3422 | hc->chan[bch->slot].conf = -1; |
3437 | mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); | 3423 | mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); |
@@ -5384,9 +5370,10 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
5384 | ent->device == PCI_DEVICE_ID_CCD_HFC8S || | 5370 | ent->device == PCI_DEVICE_ID_CCD_HFC8S || |
5385 | ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { | 5371 | ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { |
5386 | printk(KERN_ERR | 5372 | printk(KERN_ERR |
5387 | "Unknown HFC multiport controller (vendor:%x device:%x " | 5373 | "Unknown HFC multiport controller (vendor:%04x device:%04x " |
5388 | "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device, | 5374 | "subvendor:%04x subdevice:%04x)\n", pdev->vendor, |
5389 | ent->subvendor, ent->subdevice); | 5375 | pdev->device, pdev->subsystem_vendor, |
5376 | pdev->subsystem_device); | ||
5390 | printk(KERN_ERR | 5377 | printk(KERN_ERR |
5391 | "Please contact the driver maintainer for support.\n"); | 5378 | "Please contact the driver maintainer for support.\n"); |
5392 | return -ENODEV; | 5379 | return -ENODEV; |
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 228ffbed1286..70e6b0e01121 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c | |||
@@ -1522,22 +1522,8 @@ deactivate_bchannel(struct bchannel *bch) | |||
1522 | u_long flags; | 1522 | u_long flags; |
1523 | 1523 | ||
1524 | spin_lock_irqsave(&hc->lock, flags); | 1524 | spin_lock_irqsave(&hc->lock, flags); |
1525 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | 1525 | mISDN_clear_bchannel(bch); |
1526 | dev_kfree_skb(bch->next_skb); | ||
1527 | bch->next_skb = NULL; | ||
1528 | } | ||
1529 | if (bch->tx_skb) { | ||
1530 | dev_kfree_skb(bch->tx_skb); | ||
1531 | bch->tx_skb = NULL; | ||
1532 | } | ||
1533 | bch->tx_idx = 0; | ||
1534 | if (bch->rx_skb) { | ||
1535 | dev_kfree_skb(bch->rx_skb); | ||
1536 | bch->rx_skb = NULL; | ||
1537 | } | ||
1538 | mode_hfcpci(bch, bch->nr, ISDN_P_NONE); | 1526 | mode_hfcpci(bch, bch->nr, ISDN_P_NONE); |
1539 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1540 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
1541 | spin_unlock_irqrestore(&hc->lock, flags); | 1527 | spin_unlock_irqrestore(&hc->lock, flags); |
1542 | } | 1528 | } |
1543 | 1529 | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 6b7704c41b94..fc46a26cb14f 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c | |||
@@ -1809,21 +1809,7 @@ deactivate_bchannel(struct bchannel *bch) | |||
1809 | hw->name, __func__, bch->nr); | 1809 | hw->name, __func__, bch->nr); |
1810 | 1810 | ||
1811 | spin_lock_irqsave(&hw->lock, flags); | 1811 | spin_lock_irqsave(&hw->lock, flags); |
1812 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | 1812 | mISDN_clear_bchannel(bch); |
1813 | dev_kfree_skb(bch->next_skb); | ||
1814 | bch->next_skb = NULL; | ||
1815 | } | ||
1816 | if (bch->tx_skb) { | ||
1817 | dev_kfree_skb(bch->tx_skb); | ||
1818 | bch->tx_skb = NULL; | ||
1819 | } | ||
1820 | bch->tx_idx = 0; | ||
1821 | if (bch->rx_skb) { | ||
1822 | dev_kfree_skb(bch->rx_skb); | ||
1823 | bch->rx_skb = NULL; | ||
1824 | } | ||
1825 | clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1826 | clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
1827 | spin_unlock_irqrestore(&hw->lock, flags); | 1813 | spin_unlock_irqrestore(&hw->lock, flags); |
1828 | hfcsusb_setup_bch(bch, ISDN_P_NONE); | 1814 | hfcsusb_setup_bch(bch, ISDN_P_NONE); |
1829 | hfcsusb_stop_endpoint(hw, bch->nr); | 1815 | hfcsusb_stop_endpoint(hw, bch->nr); |
diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h new file mode 100644 index 000000000000..b438981107ae --- /dev/null +++ b/drivers/isdn/hardware/mISDN/iohelper.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * iohelper.h | ||
3 | * helper for define functions to access ISDN hardware | ||
4 | * supported are memory mapped IO | ||
5 | * indirect port IO (one port for address, one for data) | ||
6 | * | ||
7 | * Author Karsten Keil <keil@isdn4linux.de> | ||
8 | * | ||
9 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef _IOHELPER_H | ||
27 | #define _IOHELPER_H | ||
28 | |||
29 | typedef u8 (read_reg_func)(void *hwp, u8 offset); | ||
30 | typedef void (write_reg_func)(void *hwp, u8 offset, u8 value); | ||
31 | typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size); | ||
32 | |||
33 | struct _ioport { | ||
34 | u32 port; | ||
35 | u32 ale; | ||
36 | }; | ||
37 | |||
38 | #define IOFUNC_IO(name, hws, ap) \ | ||
39 | static u8 Read##name##_IO(void *p, u8 off) {\ | ||
40 | struct hws *hw = p;\ | ||
41 | return inb(hw->ap.port + off);\ | ||
42 | } \ | ||
43 | static void Write##name##_IO(void *p, u8 off, u8 val) {\ | ||
44 | struct hws *hw = p;\ | ||
45 | outb(val, hw->ap.port + off);\ | ||
46 | } \ | ||
47 | static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\ | ||
48 | struct hws *hw = p;\ | ||
49 | insb(hw->ap.port + off, dp, size);\ | ||
50 | } \ | ||
51 | static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\ | ||
52 | struct hws *hw = p;\ | ||
53 | outsb(hw->ap.port + off, dp, size);\ | ||
54 | } | ||
55 | |||
56 | #define IOFUNC_IND(name, hws, ap) \ | ||
57 | static u8 Read##name##_IND(void *p, u8 off) {\ | ||
58 | struct hws *hw = p;\ | ||
59 | outb(off, hw->ap.ale);\ | ||
60 | return inb(hw->ap.port);\ | ||
61 | } \ | ||
62 | static void Write##name##_IND(void *p, u8 off, u8 val) {\ | ||
63 | struct hws *hw = p;\ | ||
64 | outb(off, hw->ap.ale);\ | ||
65 | outb(val, hw->ap.port);\ | ||
66 | } \ | ||
67 | static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\ | ||
68 | struct hws *hw = p;\ | ||
69 | outb(off, hw->ap.ale);\ | ||
70 | insb(hw->ap.port, dp, size);\ | ||
71 | } \ | ||
72 | static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\ | ||
73 | struct hws *hw = p;\ | ||
74 | outb(off, hw->ap.ale);\ | ||
75 | outsb(hw->ap.port, dp, size);\ | ||
76 | } | ||
77 | |||
78 | #define IOFUNC_MEMIO(name, hws, typ, adr) \ | ||
79 | static u8 Read##name##_MIO(void *p, u8 off) {\ | ||
80 | struct hws *hw = p;\ | ||
81 | return readb(((typ *)hw->adr) + off);\ | ||
82 | } \ | ||
83 | static void Write##name##_MIO(void *p, u8 off, u8 val) {\ | ||
84 | struct hws *hw = p;\ | ||
85 | writeb(val, ((typ *)hw->adr) + off);\ | ||
86 | } \ | ||
87 | static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ | ||
88 | struct hws *hw = p;\ | ||
89 | while (size--)\ | ||
90 | *dp++ = readb(((typ *)hw->adr) + off);\ | ||
91 | } \ | ||
92 | static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ | ||
93 | struct hws *hw = p;\ | ||
94 | while (size--)\ | ||
95 | writeb(*dp++, ((typ *)hw->adr) + off);\ | ||
96 | } | ||
97 | |||
98 | #define ASSIGN_FUNC(typ, name, dest) do {\ | ||
99 | dest.read_reg = &Read##name##_##typ;\ | ||
100 | dest.write_reg = &Write##name##_##typ;\ | ||
101 | dest.read_fifo = &ReadFiFo##name##_##typ;\ | ||
102 | dest.write_fifo = &WriteFiFo##name##_##typ;\ | ||
103 | } while (0) | ||
104 | #define ASSIGN_FUNC_IPAC(typ, target) do {\ | ||
105 | ASSIGN_FUNC(typ, ISAC, target.isac);\ | ||
106 | ASSIGN_FUNC(typ, IPAC, target);\ | ||
107 | } while (0) | ||
108 | |||
109 | #endif | ||
diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h new file mode 100644 index 000000000000..74a6ccf9065c --- /dev/null +++ b/drivers/isdn/hardware/mISDN/ipac.h | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * | ||
3 | * ipac.h Defines for the Infineon (former Siemens) ISDN | ||
4 | * chip series | ||
5 | * | ||
6 | * Author Karsten Keil <keil@isdn4linux.de> | ||
7 | * | ||
8 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "iohelper.h" | ||
26 | |||
27 | struct isac_hw { | ||
28 | struct dchannel dch; | ||
29 | u32 type; | ||
30 | u32 off; /* offset to isac regs */ | ||
31 | char *name; | ||
32 | spinlock_t *hwlock; /* lock HW acccess */ | ||
33 | read_reg_func *read_reg; | ||
34 | write_reg_func *write_reg; | ||
35 | fifo_func *read_fifo; | ||
36 | fifo_func *write_fifo; | ||
37 | int (*monitor)(void *, u32, u8 *, int); | ||
38 | void (*release)(struct isac_hw *); | ||
39 | int (*init)(struct isac_hw *); | ||
40 | int (*ctrl)(struct isac_hw *, u32, u_long); | ||
41 | int (*open)(struct isac_hw *, struct channel_req *); | ||
42 | u8 *mon_tx; | ||
43 | u8 *mon_rx; | ||
44 | int mon_txp; | ||
45 | int mon_txc; | ||
46 | int mon_rxp; | ||
47 | struct arcofi_msg *arcofi_list; | ||
48 | struct timer_list arcofitimer; | ||
49 | wait_queue_head_t arcofi_wait; | ||
50 | u8 arcofi_bc; | ||
51 | u8 arcofi_state; | ||
52 | u8 mocr; | ||
53 | u8 adf2; | ||
54 | u8 state; | ||
55 | }; | ||
56 | |||
57 | struct ipac_hw; | ||
58 | |||
59 | struct hscx_hw { | ||
60 | struct bchannel bch; | ||
61 | struct ipac_hw *ip; | ||
62 | u8 fifo_size; | ||
63 | u8 off; /* offset to ICA or ICB */ | ||
64 | u8 slot; | ||
65 | char log[64]; | ||
66 | }; | ||
67 | |||
68 | struct ipac_hw { | ||
69 | struct isac_hw isac; | ||
70 | struct hscx_hw hscx[2]; | ||
71 | char *name; | ||
72 | void *hw; | ||
73 | spinlock_t *hwlock; /* lock HW acccess */ | ||
74 | struct module *owner; | ||
75 | u32 type; | ||
76 | read_reg_func *read_reg; | ||
77 | write_reg_func *write_reg; | ||
78 | fifo_func *read_fifo; | ||
79 | fifo_func *write_fifo; | ||
80 | void (*release)(struct ipac_hw *); | ||
81 | int (*init)(struct ipac_hw *); | ||
82 | int (*ctrl)(struct ipac_hw *, u32, u_long); | ||
83 | u8 conf; | ||
84 | }; | ||
85 | |||
86 | #define IPAC_TYPE_ISAC 0x0010 | ||
87 | #define IPAC_TYPE_IPAC 0x0020 | ||
88 | #define IPAC_TYPE_ISACX 0x0040 | ||
89 | #define IPAC_TYPE_IPACX 0x0080 | ||
90 | #define IPAC_TYPE_HSCX 0x0100 | ||
91 | |||
92 | #define ISAC_USE_ARCOFI 0x1000 | ||
93 | |||
94 | /* Monitor functions */ | ||
95 | #define MONITOR_RX_0 0x1000 | ||
96 | #define MONITOR_RX_1 0x1001 | ||
97 | #define MONITOR_TX_0 0x2000 | ||
98 | #define MONITOR_TX_1 0x2001 | ||
99 | |||
100 | /* All registers original Siemens Spec */ | ||
101 | /* IPAC/ISAC registers */ | ||
102 | #define ISAC_MASK 0x20 | ||
103 | #define ISAC_ISTA 0x20 | ||
104 | #define ISAC_STAR 0x21 | ||
105 | #define ISAC_CMDR 0x21 | ||
106 | #define ISAC_EXIR 0x24 | ||
107 | #define ISAC_ADF2 0x39 | ||
108 | #define ISAC_SPCR 0x30 | ||
109 | #define ISAC_ADF1 0x38 | ||
110 | #define ISAC_CIR0 0x31 | ||
111 | #define ISAC_CIX0 0x31 | ||
112 | #define ISAC_CIR1 0x33 | ||
113 | #define ISAC_CIX1 0x33 | ||
114 | #define ISAC_STCR 0x37 | ||
115 | #define ISAC_MODE 0x22 | ||
116 | #define ISAC_RSTA 0x27 | ||
117 | #define ISAC_RBCL 0x25 | ||
118 | #define ISAC_RBCH 0x2A | ||
119 | #define ISAC_TIMR 0x23 | ||
120 | #define ISAC_SQXR 0x3b | ||
121 | #define ISAC_SQRR 0x3b | ||
122 | #define ISAC_MOSR 0x3a | ||
123 | #define ISAC_MOCR 0x3a | ||
124 | #define ISAC_MOR0 0x32 | ||
125 | #define ISAC_MOX0 0x32 | ||
126 | #define ISAC_MOR1 0x34 | ||
127 | #define ISAC_MOX1 0x34 | ||
128 | |||
129 | #define ISAC_RBCH_XAC 0x80 | ||
130 | |||
131 | #define IPAC_D_TIN2 0x01 | ||
132 | |||
133 | /* IPAC/HSCX */ | ||
134 | #define IPAC_ISTAB 0x20 /* RD */ | ||
135 | #define IPAC_MASKB 0x20 /* WR */ | ||
136 | #define IPAC_STARB 0x21 /* RD */ | ||
137 | #define IPAC_CMDRB 0x21 /* WR */ | ||
138 | #define IPAC_MODEB 0x22 /* R/W */ | ||
139 | #define IPAC_EXIRB 0x24 /* RD */ | ||
140 | #define IPAC_RBCLB 0x25 /* RD */ | ||
141 | #define IPAC_RAH1 0x26 /* WR */ | ||
142 | #define IPAC_RAH2 0x27 /* WR */ | ||
143 | #define IPAC_RSTAB 0x27 /* RD */ | ||
144 | #define IPAC_RAL1 0x28 /* R/W */ | ||
145 | #define IPAC_RAL2 0x29 /* WR */ | ||
146 | #define IPAC_RHCRB 0x29 /* RD */ | ||
147 | #define IPAC_XBCL 0x2A /* WR */ | ||
148 | #define IPAC_CCR2 0x2C /* R/W */ | ||
149 | #define IPAC_RBCHB 0x2D /* RD */ | ||
150 | #define IPAC_XBCH 0x2D /* WR */ | ||
151 | #define HSCX_VSTR 0x2E /* RD */ | ||
152 | #define IPAC_RLCR 0x2E /* WR */ | ||
153 | #define IPAC_CCR1 0x2F /* R/W */ | ||
154 | #define IPAC_TSAX 0x30 /* WR */ | ||
155 | #define IPAC_TSAR 0x31 /* WR */ | ||
156 | #define IPAC_XCCR 0x32 /* WR */ | ||
157 | #define IPAC_RCCR 0x33 /* WR */ | ||
158 | |||
159 | /* IPAC_ISTAB/IPAC_MASKB bits */ | ||
160 | #define IPAC_B_XPR 0x10 | ||
161 | #define IPAC_B_RPF 0x40 | ||
162 | #define IPAC_B_RME 0x80 | ||
163 | #define IPAC_B_ON 0x2F | ||
164 | |||
165 | /* IPAC_EXIRB bits */ | ||
166 | #define IPAC_B_RFS 0x04 | ||
167 | #define IPAC_B_RFO 0x10 | ||
168 | #define IPAC_B_XDU 0x40 | ||
169 | #define IPAC_B_XMR 0x80 | ||
170 | |||
171 | /* IPAC special registers */ | ||
172 | #define IPAC_CONF 0xC0 /* R/W */ | ||
173 | #define IPAC_ISTA 0xC1 /* RD */ | ||
174 | #define IPAC_MASK 0xC1 /* WR */ | ||
175 | #define IPAC_ID 0xC2 /* RD */ | ||
176 | #define IPAC_ACFG 0xC3 /* R/W */ | ||
177 | #define IPAC_AOE 0xC4 /* R/W */ | ||
178 | #define IPAC_ARX 0xC5 /* RD */ | ||
179 | #define IPAC_ATX 0xC5 /* WR */ | ||
180 | #define IPAC_PITA1 0xC6 /* R/W */ | ||
181 | #define IPAC_PITA2 0xC7 /* R/W */ | ||
182 | #define IPAC_POTA1 0xC8 /* R/W */ | ||
183 | #define IPAC_POTA2 0xC9 /* R/W */ | ||
184 | #define IPAC_PCFG 0xCA /* R/W */ | ||
185 | #define IPAC_SCFG 0xCB /* R/W */ | ||
186 | #define IPAC_TIMR2 0xCC /* R/W */ | ||
187 | |||
188 | /* IPAC_ISTA/_MASK bits */ | ||
189 | #define IPAC__EXB 0x01 | ||
190 | #define IPAC__ICB 0x02 | ||
191 | #define IPAC__EXA 0x04 | ||
192 | #define IPAC__ICA 0x08 | ||
193 | #define IPAC__EXD 0x10 | ||
194 | #define IPAC__ICD 0x20 | ||
195 | #define IPAC__INT0 0x40 | ||
196 | #define IPAC__INT1 0x80 | ||
197 | #define IPAC__ON 0xC0 | ||
198 | |||
199 | /* HSCX ISTA/MASK bits */ | ||
200 | #define HSCX__EXB 0x01 | ||
201 | #define HSCX__EXA 0x02 | ||
202 | #define HSCX__ICA 0x04 | ||
203 | |||
204 | /* ISAC/ISACX/IPAC/IPACX L1 commands */ | ||
205 | #define ISAC_CMD_TIM 0x0 | ||
206 | #define ISAC_CMD_RS 0x1 | ||
207 | #define ISAC_CMD_SCZ 0x4 | ||
208 | #define ISAC_CMD_SSZ 0x2 | ||
209 | #define ISAC_CMD_AR8 0x8 | ||
210 | #define ISAC_CMD_AR10 0x9 | ||
211 | #define ISAC_CMD_ARL 0xA | ||
212 | #define ISAC_CMD_DUI 0xF | ||
213 | |||
214 | /* ISAC/ISACX/IPAC/IPACX L1 indications */ | ||
215 | #define ISAC_IND_RS 0x1 | ||
216 | #define ISAC_IND_PU 0x7 | ||
217 | #define ISAC_IND_DR 0x0 | ||
218 | #define ISAC_IND_SD 0x2 | ||
219 | #define ISAC_IND_DIS 0x3 | ||
220 | #define ISAC_IND_EI 0x6 | ||
221 | #define ISAC_IND_RSY 0x4 | ||
222 | #define ISAC_IND_ARD 0x8 | ||
223 | #define ISAC_IND_TI 0xA | ||
224 | #define ISAC_IND_ATI 0xB | ||
225 | #define ISAC_IND_AI8 0xC | ||
226 | #define ISAC_IND_AI10 0xD | ||
227 | #define ISAC_IND_DID 0xF | ||
228 | |||
229 | /* the new ISACX / IPACX */ | ||
230 | /* D-channel registers */ | ||
231 | #define ISACX_RFIFOD 0x00 /* RD */ | ||
232 | #define ISACX_XFIFOD 0x00 /* WR */ | ||
233 | #define ISACX_ISTAD 0x20 /* RD */ | ||
234 | #define ISACX_MASKD 0x20 /* WR */ | ||
235 | #define ISACX_STARD 0x21 /* RD */ | ||
236 | #define ISACX_CMDRD 0x21 /* WR */ | ||
237 | #define ISACX_MODED 0x22 /* R/W */ | ||
238 | #define ISACX_EXMD1 0x23 /* R/W */ | ||
239 | #define ISACX_TIMR1 0x24 /* R/W */ | ||
240 | #define ISACX_SAP1 0x25 /* WR */ | ||
241 | #define ISACX_SAP2 0x26 /* WR */ | ||
242 | #define ISACX_RBCLD 0x26 /* RD */ | ||
243 | #define ISACX_RBCHD 0x27 /* RD */ | ||
244 | #define ISACX_TEI1 0x27 /* WR */ | ||
245 | #define ISACX_TEI2 0x28 /* WR */ | ||
246 | #define ISACX_RSTAD 0x28 /* RD */ | ||
247 | #define ISACX_TMD 0x29 /* R/W */ | ||
248 | #define ISACX_CIR0 0x2E /* RD */ | ||
249 | #define ISACX_CIX0 0x2E /* WR */ | ||
250 | #define ISACX_CIR1 0x2F /* RD */ | ||
251 | #define ISACX_CIX1 0x2F /* WR */ | ||
252 | |||
253 | /* Transceiver registers */ | ||
254 | #define ISACX_TR_CONF0 0x30 /* R/W */ | ||
255 | #define ISACX_TR_CONF1 0x31 /* R/W */ | ||
256 | #define ISACX_TR_CONF2 0x32 /* R/W */ | ||
257 | #define ISACX_TR_STA 0x33 /* RD */ | ||
258 | #define ISACX_TR_CMD 0x34 /* R/W */ | ||
259 | #define ISACX_SQRR1 0x35 /* RD */ | ||
260 | #define ISACX_SQXR1 0x35 /* WR */ | ||
261 | #define ISACX_SQRR2 0x36 /* RD */ | ||
262 | #define ISACX_SQXR2 0x36 /* WR */ | ||
263 | #define ISACX_SQRR3 0x37 /* RD */ | ||
264 | #define ISACX_SQXR3 0x37 /* WR */ | ||
265 | #define ISACX_ISTATR 0x38 /* RD */ | ||
266 | #define ISACX_MASKTR 0x39 /* R/W */ | ||
267 | #define ISACX_TR_MODE 0x3A /* R/W */ | ||
268 | #define ISACX_ACFG1 0x3C /* R/W */ | ||
269 | #define ISACX_ACFG2 0x3D /* R/W */ | ||
270 | #define ISACX_AOE 0x3E /* R/W */ | ||
271 | #define ISACX_ARX 0x3F /* RD */ | ||
272 | #define ISACX_ATX 0x3F /* WR */ | ||
273 | |||
274 | /* IOM: Timeslot, DPS, CDA */ | ||
275 | #define ISACX_CDA10 0x40 /* R/W */ | ||
276 | #define ISACX_CDA11 0x41 /* R/W */ | ||
277 | #define ISACX_CDA20 0x42 /* R/W */ | ||
278 | #define ISACX_CDA21 0x43 /* R/W */ | ||
279 | #define ISACX_CDA_TSDP10 0x44 /* R/W */ | ||
280 | #define ISACX_CDA_TSDP11 0x45 /* R/W */ | ||
281 | #define ISACX_CDA_TSDP20 0x46 /* R/W */ | ||
282 | #define ISACX_CDA_TSDP21 0x47 /* R/W */ | ||
283 | #define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */ | ||
284 | #define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */ | ||
285 | #define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */ | ||
286 | #define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */ | ||
287 | #define ISACX_TR_TSDP_BC1 0x4C /* R/W */ | ||
288 | #define ISACX_TR_TSDP_BC2 0x4D /* R/W */ | ||
289 | #define ISACX_CDA1_CR 0x4E /* R/W */ | ||
290 | #define ISACX_CDA2_CR 0x4F /* R/W */ | ||
291 | |||
292 | /* IOM: Contol, Sync transfer, Monitor */ | ||
293 | #define ISACX_TR_CR 0x50 /* R/W */ | ||
294 | #define ISACX_TRC_CR 0x50 /* R/W */ | ||
295 | #define ISACX_BCHA_CR 0x51 /* R/W */ | ||
296 | #define ISACX_BCHB_CR 0x52 /* R/W */ | ||
297 | #define ISACX_DCI_CR 0x53 /* R/W */ | ||
298 | #define ISACX_DCIC_CR 0x53 /* R/W */ | ||
299 | #define ISACX_MON_CR 0x54 /* R/W */ | ||
300 | #define ISACX_SDS1_CR 0x55 /* R/W */ | ||
301 | #define ISACX_SDS2_CR 0x56 /* R/W */ | ||
302 | #define ISACX_IOM_CR 0x57 /* R/W */ | ||
303 | #define ISACX_STI 0x58 /* RD */ | ||
304 | #define ISACX_ASTI 0x58 /* WR */ | ||
305 | #define ISACX_MSTI 0x59 /* R/W */ | ||
306 | #define ISACX_SDS_CONF 0x5A /* R/W */ | ||
307 | #define ISACX_MCDA 0x5B /* RD */ | ||
308 | #define ISACX_MOR 0x5C /* RD */ | ||
309 | #define ISACX_MOX 0x5C /* WR */ | ||
310 | #define ISACX_MOSR 0x5D /* RD */ | ||
311 | #define ISACX_MOCR 0x5E /* R/W */ | ||
312 | #define ISACX_MSTA 0x5F /* RD */ | ||
313 | #define ISACX_MCONF 0x5F /* WR */ | ||
314 | |||
315 | /* Interrupt and general registers */ | ||
316 | #define ISACX_ISTA 0x60 /* RD */ | ||
317 | #define ISACX_MASK 0x60 /* WR */ | ||
318 | #define ISACX_AUXI 0x61 /* RD */ | ||
319 | #define ISACX_AUXM 0x61 /* WR */ | ||
320 | #define ISACX_MODE1 0x62 /* R/W */ | ||
321 | #define ISACX_MODE2 0x63 /* R/W */ | ||
322 | #define ISACX_ID 0x64 /* RD */ | ||
323 | #define ISACX_SRES 0x64 /* WR */ | ||
324 | #define ISACX_TIMR2 0x65 /* R/W */ | ||
325 | |||
326 | /* Register Bits */ | ||
327 | /* ISACX/IPACX _ISTAD (R) and _MASKD (W) */ | ||
328 | #define ISACX_D_XDU 0x04 | ||
329 | #define ISACX_D_XMR 0x08 | ||
330 | #define ISACX_D_XPR 0x10 | ||
331 | #define ISACX_D_RFO 0x20 | ||
332 | #define ISACX_D_RPF 0x40 | ||
333 | #define ISACX_D_RME 0x80 | ||
334 | |||
335 | /* ISACX/IPACX _ISTA (R) and _MASK (W) */ | ||
336 | #define ISACX__ICD 0x01 | ||
337 | #define ISACX__MOS 0x02 | ||
338 | #define ISACX__TRAN 0x04 | ||
339 | #define ISACX__AUX 0x08 | ||
340 | #define ISACX__CIC 0x10 | ||
341 | #define ISACX__ST 0x20 | ||
342 | #define IPACX__ICB 0x40 | ||
343 | #define IPACX__ICA 0x80 | ||
344 | #define IPACX__ON 0x2C | ||
345 | |||
346 | /* ISACX/IPACX _CMDRD (W) */ | ||
347 | #define ISACX_CMDRD_XRES 0x01 | ||
348 | #define ISACX_CMDRD_XME 0x02 | ||
349 | #define ISACX_CMDRD_XTF 0x08 | ||
350 | #define ISACX_CMDRD_STI 0x10 | ||
351 | #define ISACX_CMDRD_RRES 0x40 | ||
352 | #define ISACX_CMDRD_RMC 0x80 | ||
353 | |||
354 | /* ISACX/IPACX _RSTAD (R) */ | ||
355 | #define ISACX_RSTAD_TA 0x01 | ||
356 | #define ISACX_RSTAD_CR 0x02 | ||
357 | #define ISACX_RSTAD_SA0 0x04 | ||
358 | #define ISACX_RSTAD_SA1 0x08 | ||
359 | #define ISACX_RSTAD_RAB 0x10 | ||
360 | #define ISACX_RSTAD_CRC 0x20 | ||
361 | #define ISACX_RSTAD_RDO 0x40 | ||
362 | #define ISACX_RSTAD_VFR 0x80 | ||
363 | |||
364 | /* ISACX/IPACX _CIR0 (R) */ | ||
365 | #define ISACX_CIR0_BAS 0x01 | ||
366 | #define ISACX_CIR0_SG 0x08 | ||
367 | #define ISACX_CIR0_CIC1 0x08 | ||
368 | #define ISACX_CIR0_CIC0 0x08 | ||
369 | |||
370 | /* B-channel registers */ | ||
371 | #define IPACX_OFF_ICA 0x70 | ||
372 | #define IPACX_OFF_ICB 0x80 | ||
373 | |||
374 | /* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */ | ||
375 | |||
376 | #define IPACX_ISTAB 0x00 /* RD */ | ||
377 | #define IPACX_MASKB 0x00 /* WR */ | ||
378 | #define IPACX_STARB 0x01 /* RD */ | ||
379 | #define IPACX_CMDRB 0x01 /* WR */ | ||
380 | #define IPACX_MODEB 0x02 /* R/W */ | ||
381 | #define IPACX_EXMB 0x03 /* R/W */ | ||
382 | #define IPACX_RAH1 0x05 /* WR */ | ||
383 | #define IPACX_RAH2 0x06 /* WR */ | ||
384 | #define IPACX_RBCLB 0x06 /* RD */ | ||
385 | #define IPACX_RBCHB 0x07 /* RD */ | ||
386 | #define IPACX_RAL1 0x07 /* WR */ | ||
387 | #define IPACX_RAL2 0x08 /* WR */ | ||
388 | #define IPACX_RSTAB 0x08 /* RD */ | ||
389 | #define IPACX_TMB 0x09 /* R/W */ | ||
390 | #define IPACX_RFIFOB 0x0A /* RD */ | ||
391 | #define IPACX_XFIFOB 0x0A /* WR */ | ||
392 | |||
393 | /* IPACX_ISTAB / IPACX_MASKB bits */ | ||
394 | #define IPACX_B_XDU 0x04 | ||
395 | #define IPACX_B_XPR 0x10 | ||
396 | #define IPACX_B_RFO 0x20 | ||
397 | #define IPACX_B_RPF 0x40 | ||
398 | #define IPACX_B_RME 0x80 | ||
399 | |||
400 | #define IPACX_B_ON 0x0B | ||
401 | |||
402 | extern int mISDNisac_init(struct isac_hw *, void *); | ||
403 | extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8); | ||
404 | extern u32 mISDNipac_init(struct ipac_hw *, void *); | ||
405 | extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int); | ||
diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h new file mode 100644 index 000000000000..4a134acd44d0 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/isar.h | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * | ||
3 | * isar.h ISAR (Siemens PSB 7110) specific defines | ||
4 | * | ||
5 | * Author Karsten Keil (keil@isdn4linux.de) | ||
6 | * | ||
7 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "iohelper.h" | ||
25 | |||
26 | struct isar_hw; | ||
27 | |||
28 | struct isar_ch { | ||
29 | struct bchannel bch; | ||
30 | struct isar_hw *is; | ||
31 | struct timer_list ftimer; | ||
32 | u8 nr; | ||
33 | u8 dpath; | ||
34 | u8 mml; | ||
35 | u8 state; | ||
36 | u8 cmd; | ||
37 | u8 mod; | ||
38 | u8 newcmd; | ||
39 | u8 newmod; | ||
40 | u8 try_mod; | ||
41 | u8 conmsg[16]; | ||
42 | }; | ||
43 | |||
44 | struct isar_hw { | ||
45 | struct isar_ch ch[2]; | ||
46 | void *hw; | ||
47 | spinlock_t *hwlock; /* lock HW acccess */ | ||
48 | char *name; | ||
49 | struct module *owner; | ||
50 | read_reg_func *read_reg; | ||
51 | write_reg_func *write_reg; | ||
52 | fifo_func *read_fifo; | ||
53 | fifo_func *write_fifo; | ||
54 | int (*ctrl)(void *, u32, u_long); | ||
55 | void (*release)(struct isar_hw *); | ||
56 | int (*init)(struct isar_hw *); | ||
57 | int (*open)(struct isar_hw *, struct channel_req *); | ||
58 | int (*firmware)(struct isar_hw *, const u8 *, int); | ||
59 | unsigned long Flags; | ||
60 | int version; | ||
61 | u8 bstat; | ||
62 | u8 iis; | ||
63 | u8 cmsb; | ||
64 | u8 clsb; | ||
65 | u8 buf[256]; | ||
66 | u8 log[256]; | ||
67 | }; | ||
68 | |||
69 | #define ISAR_IRQMSK 0x04 | ||
70 | #define ISAR_IRQSTA 0x04 | ||
71 | #define ISAR_IRQBIT 0x75 | ||
72 | #define ISAR_CTRL_H 0x61 | ||
73 | #define ISAR_CTRL_L 0x60 | ||
74 | #define ISAR_IIS 0x58 | ||
75 | #define ISAR_IIA 0x58 | ||
76 | #define ISAR_HIS 0x50 | ||
77 | #define ISAR_HIA 0x50 | ||
78 | #define ISAR_MBOX 0x4c | ||
79 | #define ISAR_WADR 0x4a | ||
80 | #define ISAR_RADR 0x48 | ||
81 | |||
82 | #define ISAR_HIS_VNR 0x14 | ||
83 | #define ISAR_HIS_DKEY 0x02 | ||
84 | #define ISAR_HIS_FIRM 0x1e | ||
85 | #define ISAR_HIS_STDSP 0x08 | ||
86 | #define ISAR_HIS_DIAG 0x05 | ||
87 | #define ISAR_HIS_P0CFG 0x3c | ||
88 | #define ISAR_HIS_P12CFG 0x24 | ||
89 | #define ISAR_HIS_SARTCFG 0x25 | ||
90 | #define ISAR_HIS_PUMPCFG 0x26 | ||
91 | #define ISAR_HIS_PUMPCTRL 0x2a | ||
92 | #define ISAR_HIS_IOM2CFG 0x27 | ||
93 | #define ISAR_HIS_IOM2REQ 0x07 | ||
94 | #define ISAR_HIS_IOM2CTRL 0x2b | ||
95 | #define ISAR_HIS_BSTREQ 0x0c | ||
96 | #define ISAR_HIS_PSTREQ 0x0e | ||
97 | #define ISAR_HIS_SDATA 0x20 | ||
98 | #define ISAR_HIS_DPS1 0x40 | ||
99 | #define ISAR_HIS_DPS2 0x80 | ||
100 | #define SET_DPS(x) ((x<<6) & 0xc0) | ||
101 | |||
102 | #define ISAR_IIS_MSCMSD 0x3f | ||
103 | #define ISAR_IIS_VNR 0x15 | ||
104 | #define ISAR_IIS_DKEY 0x03 | ||
105 | #define ISAR_IIS_FIRM 0x1f | ||
106 | #define ISAR_IIS_STDSP 0x09 | ||
107 | #define ISAR_IIS_DIAG 0x25 | ||
108 | #define ISAR_IIS_GSTEV 0x00 | ||
109 | #define ISAR_IIS_BSTEV 0x28 | ||
110 | #define ISAR_IIS_BSTRSP 0x2c | ||
111 | #define ISAR_IIS_PSTRSP 0x2e | ||
112 | #define ISAR_IIS_PSTEV 0x2a | ||
113 | #define ISAR_IIS_IOM2RSP 0x27 | ||
114 | #define ISAR_IIS_RDATA 0x20 | ||
115 | #define ISAR_IIS_INVMSG 0x3f | ||
116 | |||
117 | #define ISAR_CTRL_SWVER 0x10 | ||
118 | #define ISAR_CTRL_STST 0x40 | ||
119 | |||
120 | #define ISAR_MSG_HWVER 0x20 | ||
121 | |||
122 | #define ISAR_DP1_USE 1 | ||
123 | #define ISAR_DP2_USE 2 | ||
124 | #define ISAR_RATE_REQ 3 | ||
125 | |||
126 | #define PMOD_DISABLE 0 | ||
127 | #define PMOD_FAX 1 | ||
128 | #define PMOD_DATAMODEM 2 | ||
129 | #define PMOD_HALFDUPLEX 3 | ||
130 | #define PMOD_V110 4 | ||
131 | #define PMOD_DTMF 5 | ||
132 | #define PMOD_DTMF_TRANS 6 | ||
133 | #define PMOD_BYPASS 7 | ||
134 | |||
135 | #define PCTRL_ORIG 0x80 | ||
136 | #define PV32P2_V23R 0x40 | ||
137 | #define PV32P2_V22A 0x20 | ||
138 | #define PV32P2_V22B 0x10 | ||
139 | #define PV32P2_V22C 0x08 | ||
140 | #define PV32P2_V21 0x02 | ||
141 | #define PV32P2_BEL 0x01 | ||
142 | |||
143 | /* LSB MSB in ISAR doc wrong !!! Arghhh */ | ||
144 | #define PV32P3_AMOD 0x80 | ||
145 | #define PV32P3_V32B 0x02 | ||
146 | #define PV32P3_V23B 0x01 | ||
147 | #define PV32P4_48 0x11 | ||
148 | #define PV32P5_48 0x05 | ||
149 | #define PV32P4_UT48 0x11 | ||
150 | #define PV32P5_UT48 0x0d | ||
151 | #define PV32P4_96 0x11 | ||
152 | #define PV32P5_96 0x03 | ||
153 | #define PV32P4_UT96 0x11 | ||
154 | #define PV32P5_UT96 0x0f | ||
155 | #define PV32P4_B96 0x91 | ||
156 | #define PV32P5_B96 0x0b | ||
157 | #define PV32P4_UTB96 0xd1 | ||
158 | #define PV32P5_UTB96 0x0f | ||
159 | #define PV32P4_120 0xb1 | ||
160 | #define PV32P5_120 0x09 | ||
161 | #define PV32P4_UT120 0xf1 | ||
162 | #define PV32P5_UT120 0x0f | ||
163 | #define PV32P4_144 0x99 | ||
164 | #define PV32P5_144 0x09 | ||
165 | #define PV32P4_UT144 0xf9 | ||
166 | #define PV32P5_UT144 0x0f | ||
167 | #define PV32P6_CTN 0x01 | ||
168 | #define PV32P6_ATN 0x02 | ||
169 | |||
170 | #define PFAXP2_CTN 0x01 | ||
171 | #define PFAXP2_ATN 0x04 | ||
172 | |||
173 | #define PSEV_10MS_TIMER 0x02 | ||
174 | #define PSEV_CON_ON 0x18 | ||
175 | #define PSEV_CON_OFF 0x19 | ||
176 | #define PSEV_V24_OFF 0x20 | ||
177 | #define PSEV_CTS_ON 0x21 | ||
178 | #define PSEV_CTS_OFF 0x22 | ||
179 | #define PSEV_DCD_ON 0x23 | ||
180 | #define PSEV_DCD_OFF 0x24 | ||
181 | #define PSEV_DSR_ON 0x25 | ||
182 | #define PSEV_DSR_OFF 0x26 | ||
183 | #define PSEV_REM_RET 0xcc | ||
184 | #define PSEV_REM_REN 0xcd | ||
185 | #define PSEV_GSTN_CLR 0xd4 | ||
186 | |||
187 | #define PSEV_RSP_READY 0xbc | ||
188 | #define PSEV_LINE_TX_H 0xb3 | ||
189 | #define PSEV_LINE_TX_B 0xb2 | ||
190 | #define PSEV_LINE_RX_H 0xb1 | ||
191 | #define PSEV_LINE_RX_B 0xb0 | ||
192 | #define PSEV_RSP_CONN 0xb5 | ||
193 | #define PSEV_RSP_DISC 0xb7 | ||
194 | #define PSEV_RSP_FCERR 0xb9 | ||
195 | #define PSEV_RSP_SILDET 0xbe | ||
196 | #define PSEV_RSP_SILOFF 0xab | ||
197 | #define PSEV_FLAGS_DET 0xba | ||
198 | |||
199 | #define PCTRL_CMD_TDTMF 0x5a | ||
200 | |||
201 | #define PCTRL_CMD_FTH 0xa7 | ||
202 | #define PCTRL_CMD_FRH 0xa5 | ||
203 | #define PCTRL_CMD_FTM 0xa8 | ||
204 | #define PCTRL_CMD_FRM 0xa6 | ||
205 | #define PCTRL_CMD_SILON 0xac | ||
206 | #define PCTRL_CMD_CONT 0xa2 | ||
207 | #define PCTRL_CMD_ESC 0xa4 | ||
208 | #define PCTRL_CMD_SILOFF 0xab | ||
209 | #define PCTRL_CMD_HALT 0xa9 | ||
210 | |||
211 | #define PCTRL_LOC_RET 0xcf | ||
212 | #define PCTRL_LOC_REN 0xce | ||
213 | |||
214 | #define SMODE_DISABLE 0 | ||
215 | #define SMODE_V14 2 | ||
216 | #define SMODE_HDLC 3 | ||
217 | #define SMODE_BINARY 4 | ||
218 | #define SMODE_FSK_V14 5 | ||
219 | |||
220 | #define SCTRL_HDMC_BOTH 0x00 | ||
221 | #define SCTRL_HDMC_DTX 0x80 | ||
222 | #define SCTRL_HDMC_DRX 0x40 | ||
223 | #define S_P1_OVSP 0x40 | ||
224 | #define S_P1_SNP 0x20 | ||
225 | #define S_P1_EOP 0x10 | ||
226 | #define S_P1_EDP 0x08 | ||
227 | #define S_P1_NSB 0x04 | ||
228 | #define S_P1_CHS_8 0x03 | ||
229 | #define S_P1_CHS_7 0x02 | ||
230 | #define S_P1_CHS_6 0x01 | ||
231 | #define S_P1_CHS_5 0x00 | ||
232 | |||
233 | #define S_P2_BFT_DEF 0x10 | ||
234 | |||
235 | #define IOM_CTRL_ENA 0x80 | ||
236 | #define IOM_CTRL_NOPCM 0x00 | ||
237 | #define IOM_CTRL_ALAW 0x02 | ||
238 | #define IOM_CTRL_ULAW 0x04 | ||
239 | #define IOM_CTRL_RCV 0x01 | ||
240 | |||
241 | #define IOM_P1_TXD 0x10 | ||
242 | |||
243 | #define HDLC_FED 0x40 | ||
244 | #define HDLC_FSD 0x20 | ||
245 | #define HDLC_FST 0x20 | ||
246 | #define HDLC_ERROR 0x1c | ||
247 | #define HDLC_ERR_FAD 0x10 | ||
248 | #define HDLC_ERR_RER 0x08 | ||
249 | #define HDLC_ERR_CER 0x04 | ||
250 | #define SART_NMD 0x01 | ||
251 | |||
252 | #define BSTAT_RDM0 0x1 | ||
253 | #define BSTAT_RDM1 0x2 | ||
254 | #define BSTAT_RDM2 0x4 | ||
255 | #define BSTAT_RDM3 0x8 | ||
256 | #define BSTEV_TBO 0x1f | ||
257 | #define BSTEV_RBO 0x2f | ||
258 | |||
259 | /* FAX State Machine */ | ||
260 | #define STFAX_NULL 0 | ||
261 | #define STFAX_READY 1 | ||
262 | #define STFAX_LINE 2 | ||
263 | #define STFAX_CONT 3 | ||
264 | #define STFAX_ACTIV 4 | ||
265 | #define STFAX_ESCAPE 5 | ||
266 | #define STFAX_SILDET 6 | ||
267 | |||
268 | extern u32 mISDNisar_init(struct isar_hw *, void *); | ||
269 | extern void mISDNisar_irq(struct isar_hw *); | ||
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c new file mode 100644 index 000000000000..62441ba53b95 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c | |||
@@ -0,0 +1,1178 @@ | |||
1 | /* | ||
2 | * mISDNinfineon.c | ||
3 | * Support for cards based on following Infineon ISDN chipsets | ||
4 | * - ISAC + HSCX | ||
5 | * - IPAC and IPAC-X | ||
6 | * - ISAC-SX + HSCX | ||
7 | * | ||
8 | * Supported cards: | ||
9 | * - Dialogic Diva 2.0 | ||
10 | * - Dialogic Diva 2.0U | ||
11 | * - Dialogic Diva 2.01 | ||
12 | * - Dialogic Diva 2.02 | ||
13 | * - Sedlbauer Speedwin | ||
14 | * - HST Saphir3 | ||
15 | * - Develo (former ELSA) Microlink PCI (Quickstep 1000) | ||
16 | * - Develo (former ELSA) Quickstep 3000 | ||
17 | * - Berkom Scitel BRIX Quadro | ||
18 | * - Dr.Neuhaus (Sagem) Niccy | ||
19 | * | ||
20 | * | ||
21 | * | ||
22 | * Author Karsten Keil <keil@isdn4linux.de> | ||
23 | * | ||
24 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
25 | * | ||
26 | * This program is free software; you can redistribute it and/or modify | ||
27 | * it under the terms of the GNU General Public License version 2 as | ||
28 | * published by the Free Software Foundation. | ||
29 | * | ||
30 | * This program is distributed in the hope that it will be useful, | ||
31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
33 | * GNU General Public License for more details. | ||
34 | * | ||
35 | * You should have received a copy of the GNU General Public License | ||
36 | * along with this program; if not, write to the Free Software | ||
37 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | #include <linux/module.h> | ||
42 | #include <linux/pci.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/mISDNhw.h> | ||
45 | #include "ipac.h" | ||
46 | |||
47 | #define INFINEON_REV "1.0" | ||
48 | |||
49 | static int inf_cnt; | ||
50 | static u32 debug; | ||
51 | static u32 irqloops = 4; | ||
52 | |||
53 | enum inf_types { | ||
54 | INF_NONE, | ||
55 | INF_DIVA20, | ||
56 | INF_DIVA20U, | ||
57 | INF_DIVA201, | ||
58 | INF_DIVA202, | ||
59 | INF_SPEEDWIN, | ||
60 | INF_SAPHIR3, | ||
61 | INF_QS1000, | ||
62 | INF_QS3000, | ||
63 | INF_NICCY, | ||
64 | INF_SCT_1, | ||
65 | INF_SCT_2, | ||
66 | INF_SCT_3, | ||
67 | INF_SCT_4, | ||
68 | INF_GAZEL_R685, | ||
69 | INF_GAZEL_R753 | ||
70 | }; | ||
71 | |||
72 | enum addr_mode { | ||
73 | AM_NONE = 0, | ||
74 | AM_IO, | ||
75 | AM_MEMIO, | ||
76 | AM_IND_IO, | ||
77 | }; | ||
78 | |||
79 | struct inf_cinfo { | ||
80 | enum inf_types typ; | ||
81 | const char *full; | ||
82 | const char *name; | ||
83 | enum addr_mode cfg_mode; | ||
84 | enum addr_mode addr_mode; | ||
85 | u8 cfg_bar; | ||
86 | u8 addr_bar; | ||
87 | void *irqfunc; | ||
88 | }; | ||
89 | |||
90 | struct _ioaddr { | ||
91 | enum addr_mode mode; | ||
92 | union { | ||
93 | void __iomem *p; | ||
94 | struct _ioport io; | ||
95 | } a; | ||
96 | }; | ||
97 | |||
98 | struct _iohandle { | ||
99 | enum addr_mode mode; | ||
100 | resource_size_t size; | ||
101 | resource_size_t start; | ||
102 | void __iomem *p; | ||
103 | }; | ||
104 | |||
105 | struct inf_hw { | ||
106 | struct list_head list; | ||
107 | struct pci_dev *pdev; | ||
108 | const struct inf_cinfo *ci; | ||
109 | char name[MISDN_MAX_IDLEN]; | ||
110 | u32 irq; | ||
111 | u32 irqcnt; | ||
112 | struct _iohandle cfg; | ||
113 | struct _iohandle addr; | ||
114 | struct _ioaddr isac; | ||
115 | struct _ioaddr hscx; | ||
116 | spinlock_t lock; /* HW access lock */ | ||
117 | struct ipac_hw ipac; | ||
118 | struct inf_hw *sc[3]; /* slave cards */ | ||
119 | }; | ||
120 | |||
121 | |||
122 | #define PCI_SUBVENDOR_HST_SAPHIR3 0x52 | ||
123 | #define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 | ||
124 | #define PCI_SUB_ID_SEDLBAUER 0x01 | ||
125 | |||
126 | static struct pci_device_id infineon_ids[] __devinitdata = { | ||
127 | { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, | ||
128 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20}, | ||
129 | { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, | ||
130 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U}, | ||
131 | { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, | ||
132 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201}, | ||
133 | { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, | ||
134 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202}, | ||
135 | { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, | ||
136 | PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0, | ||
137 | INF_SPEEDWIN}, | ||
138 | { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, | ||
139 | PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3}, | ||
140 | { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, | ||
141 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000}, | ||
142 | { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000, | ||
143 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000}, | ||
144 | { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, | ||
145 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY}, | ||
146 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, | ||
147 | PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0, | ||
148 | INF_SCT_1}, | ||
149 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685, | ||
150 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685}, | ||
151 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753, | ||
152 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, | ||
153 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, | ||
154 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, | ||
155 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC, | ||
156 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, | ||
157 | { } | ||
158 | }; | ||
159 | MODULE_DEVICE_TABLE(pci, infineon_ids); | ||
160 | |||
161 | /* PCI interface specific defines */ | ||
162 | /* Diva 2.0/2.0U */ | ||
163 | #define DIVA_HSCX_PORT 0x00 | ||
164 | #define DIVA_HSCX_ALE 0x04 | ||
165 | #define DIVA_ISAC_PORT 0x08 | ||
166 | #define DIVA_ISAC_ALE 0x0C | ||
167 | #define DIVA_PCI_CTRL 0x10 | ||
168 | |||
169 | /* DIVA_PCI_CTRL bits */ | ||
170 | #define DIVA_IRQ_BIT 0x01 | ||
171 | #define DIVA_RESET_BIT 0x08 | ||
172 | #define DIVA_EEPROM_CLK 0x40 | ||
173 | #define DIVA_LED_A 0x10 | ||
174 | #define DIVA_LED_B 0x20 | ||
175 | #define DIVA_IRQ_CLR 0x80 | ||
176 | |||
177 | /* Diva 2.01/2.02 */ | ||
178 | /* Siemens PITA */ | ||
179 | #define PITA_ICR_REG 0x00 | ||
180 | #define PITA_INT0_STATUS 0x02 | ||
181 | |||
182 | #define PITA_MISC_REG 0x1c | ||
183 | #define PITA_PARA_SOFTRESET 0x01000000 | ||
184 | #define PITA_SER_SOFTRESET 0x02000000 | ||
185 | #define PITA_PARA_MPX_MODE 0x04000000 | ||
186 | #define PITA_INT0_ENABLE 0x00020000 | ||
187 | |||
188 | /* TIGER 100 Registers */ | ||
189 | #define TIGER_RESET_ADDR 0x00 | ||
190 | #define TIGER_EXTERN_RESET 0x01 | ||
191 | #define TIGER_AUX_CTRL 0x02 | ||
192 | #define TIGER_AUX_DATA 0x03 | ||
193 | #define TIGER_AUX_IRQMASK 0x05 | ||
194 | #define TIGER_AUX_STATUS 0x07 | ||
195 | |||
196 | /* Tiger AUX BITs */ | ||
197 | #define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */ | ||
198 | #define TIGER_IRQ_BIT 0x02 | ||
199 | |||
200 | #define TIGER_IPAC_ALE 0xC0 | ||
201 | #define TIGER_IPAC_PORT 0xC8 | ||
202 | |||
203 | /* ELSA (now Develo) PCI cards */ | ||
204 | #define ELSA_IRQ_ADDR 0x4c | ||
205 | #define ELSA_IRQ_MASK 0x04 | ||
206 | #define QS1000_IRQ_OFF 0x01 | ||
207 | #define QS3000_IRQ_OFF 0x03 | ||
208 | #define QS1000_IRQ_ON 0x41 | ||
209 | #define QS3000_IRQ_ON 0x43 | ||
210 | |||
211 | /* Dr Neuhaus/Sagem Niccy */ | ||
212 | #define NICCY_ISAC_PORT 0x00 | ||
213 | #define NICCY_HSCX_PORT 0x01 | ||
214 | #define NICCY_ISAC_ALE 0x02 | ||
215 | #define NICCY_HSCX_ALE 0x03 | ||
216 | |||
217 | #define NICCY_IRQ_CTRL_REG 0x38 | ||
218 | #define NICCY_IRQ_ENABLE 0x001f00 | ||
219 | #define NICCY_IRQ_DISABLE 0xff0000 | ||
220 | #define NICCY_IRQ_BIT 0x800000 | ||
221 | |||
222 | |||
223 | /* Scitel PLX */ | ||
224 | #define SCT_PLX_IRQ_ADDR 0x4c | ||
225 | #define SCT_PLX_RESET_ADDR 0x50 | ||
226 | #define SCT_PLX_IRQ_ENABLE 0x41 | ||
227 | #define SCT_PLX_RESET_BIT 0x04 | ||
228 | |||
229 | /* Gazel */ | ||
230 | #define GAZEL_IPAC_DATA_PORT 0x04 | ||
231 | /* Gazel PLX */ | ||
232 | #define GAZEL_CNTRL 0x50 | ||
233 | #define GAZEL_RESET 0x04 | ||
234 | #define GAZEL_RESET_9050 0x40000000 | ||
235 | #define GAZEL_INCSR 0x4C | ||
236 | #define GAZEL_ISAC_EN 0x08 | ||
237 | #define GAZEL_INT_ISAC 0x20 | ||
238 | #define GAZEL_HSCX_EN 0x01 | ||
239 | #define GAZEL_INT_HSCX 0x04 | ||
240 | #define GAZEL_PCI_EN 0x40 | ||
241 | #define GAZEL_IPAC_EN 0x03 | ||
242 | |||
243 | |||
244 | static LIST_HEAD(Cards); | ||
245 | static DEFINE_RWLOCK(card_lock); /* protect Cards */ | ||
246 | |||
247 | static void | ||
248 | _set_debug(struct inf_hw *card) | ||
249 | { | ||
250 | card->ipac.isac.dch.debug = debug; | ||
251 | card->ipac.hscx[0].bch.debug = debug; | ||
252 | card->ipac.hscx[1].bch.debug = debug; | ||
253 | } | ||
254 | |||
255 | static int | ||
256 | set_debug(const char *val, struct kernel_param *kp) | ||
257 | { | ||
258 | int ret; | ||
259 | struct inf_hw *card; | ||
260 | |||
261 | ret = param_set_uint(val, kp); | ||
262 | if (!ret) { | ||
263 | read_lock(&card_lock); | ||
264 | list_for_each_entry(card, &Cards, list) | ||
265 | _set_debug(card); | ||
266 | read_unlock(&card_lock); | ||
267 | } | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | MODULE_AUTHOR("Karsten Keil"); | ||
272 | MODULE_LICENSE("GPL v2"); | ||
273 | MODULE_VERSION(INFINEON_REV); | ||
274 | module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); | ||
275 | MODULE_PARM_DESC(debug, "infineon debug mask"); | ||
276 | module_param(irqloops, uint, S_IRUGO | S_IWUSR); | ||
277 | MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)"); | ||
278 | |||
279 | /* Interface functions */ | ||
280 | |||
281 | IOFUNC_IO(ISAC, inf_hw, isac.a.io) | ||
282 | IOFUNC_IO(IPAC, inf_hw, hscx.a.io) | ||
283 | IOFUNC_IND(ISAC, inf_hw, isac.a.io) | ||
284 | IOFUNC_IND(IPAC, inf_hw, hscx.a.io) | ||
285 | IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p) | ||
286 | IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p) | ||
287 | |||
288 | static irqreturn_t | ||
289 | diva_irq(int intno, void *dev_id) | ||
290 | { | ||
291 | struct inf_hw *hw = dev_id; | ||
292 | u8 val; | ||
293 | |||
294 | spin_lock(&hw->lock); | ||
295 | val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL); | ||
296 | if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */ | ||
297 | spin_unlock(&hw->lock); | ||
298 | return IRQ_NONE; /* shared */ | ||
299 | } | ||
300 | hw->irqcnt++; | ||
301 | mISDNipac_irq(&hw->ipac, irqloops); | ||
302 | spin_unlock(&hw->lock); | ||
303 | return IRQ_HANDLED; | ||
304 | } | ||
305 | |||
306 | static irqreturn_t | ||
307 | diva20x_irq(int intno, void *dev_id) | ||
308 | { | ||
309 | struct inf_hw *hw = dev_id; | ||
310 | u8 val; | ||
311 | |||
312 | spin_lock(&hw->lock); | ||
313 | val = readb(hw->cfg.p); | ||
314 | if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */ | ||
315 | spin_unlock(&hw->lock); | ||
316 | return IRQ_NONE; /* shared */ | ||
317 | } | ||
318 | hw->irqcnt++; | ||
319 | mISDNipac_irq(&hw->ipac, irqloops); | ||
320 | writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */ | ||
321 | spin_unlock(&hw->lock); | ||
322 | return IRQ_HANDLED; | ||
323 | } | ||
324 | |||
325 | static irqreturn_t | ||
326 | tiger_irq(int intno, void *dev_id) | ||
327 | { | ||
328 | struct inf_hw *hw = dev_id; | ||
329 | u8 val; | ||
330 | |||
331 | spin_lock(&hw->lock); | ||
332 | val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS); | ||
333 | if (val & TIGER_IRQ_BIT) { /* for us or shared ? */ | ||
334 | spin_unlock(&hw->lock); | ||
335 | return IRQ_NONE; /* shared */ | ||
336 | } | ||
337 | hw->irqcnt++; | ||
338 | mISDNipac_irq(&hw->ipac, irqloops); | ||
339 | spin_unlock(&hw->lock); | ||
340 | return IRQ_HANDLED; | ||
341 | } | ||
342 | |||
343 | static irqreturn_t | ||
344 | elsa_irq(int intno, void *dev_id) | ||
345 | { | ||
346 | struct inf_hw *hw = dev_id; | ||
347 | u8 val; | ||
348 | |||
349 | spin_lock(&hw->lock); | ||
350 | val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR); | ||
351 | if (!(val & ELSA_IRQ_MASK)) { | ||
352 | spin_unlock(&hw->lock); | ||
353 | return IRQ_NONE; /* shared */ | ||
354 | } | ||
355 | hw->irqcnt++; | ||
356 | mISDNipac_irq(&hw->ipac, irqloops); | ||
357 | spin_unlock(&hw->lock); | ||
358 | return IRQ_HANDLED; | ||
359 | } | ||
360 | |||
361 | static irqreturn_t | ||
362 | niccy_irq(int intno, void *dev_id) | ||
363 | { | ||
364 | struct inf_hw *hw = dev_id; | ||
365 | u32 val; | ||
366 | |||
367 | spin_lock(&hw->lock); | ||
368 | val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); | ||
369 | if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */ | ||
370 | spin_unlock(&hw->lock); | ||
371 | return IRQ_NONE; /* shared */ | ||
372 | } | ||
373 | outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); | ||
374 | hw->irqcnt++; | ||
375 | mISDNipac_irq(&hw->ipac, irqloops); | ||
376 | spin_unlock(&hw->lock); | ||
377 | return IRQ_HANDLED; | ||
378 | } | ||
379 | |||
380 | static irqreturn_t | ||
381 | gazel_irq(int intno, void *dev_id) | ||
382 | { | ||
383 | struct inf_hw *hw = dev_id; | ||
384 | irqreturn_t ret; | ||
385 | |||
386 | spin_lock(&hw->lock); | ||
387 | ret = mISDNipac_irq(&hw->ipac, irqloops); | ||
388 | spin_unlock(&hw->lock); | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | static irqreturn_t | ||
393 | ipac_irq(int intno, void *dev_id) | ||
394 | { | ||
395 | struct inf_hw *hw = dev_id; | ||
396 | u8 val; | ||
397 | |||
398 | spin_lock(&hw->lock); | ||
399 | val = hw->ipac.read_reg(hw, IPAC_ISTA); | ||
400 | if (!(val & 0x3f)) { | ||
401 | spin_unlock(&hw->lock); | ||
402 | return IRQ_NONE; /* shared */ | ||
403 | } | ||
404 | hw->irqcnt++; | ||
405 | mISDNipac_irq(&hw->ipac, irqloops); | ||
406 | spin_unlock(&hw->lock); | ||
407 | return IRQ_HANDLED; | ||
408 | } | ||
409 | |||
410 | static void | ||
411 | enable_hwirq(struct inf_hw *hw) | ||
412 | { | ||
413 | u16 w; | ||
414 | u32 val; | ||
415 | |||
416 | switch (hw->ci->typ) { | ||
417 | case INF_DIVA201: | ||
418 | case INF_DIVA202: | ||
419 | writel(PITA_INT0_ENABLE, hw->cfg.p); | ||
420 | break; | ||
421 | case INF_SPEEDWIN: | ||
422 | case INF_SAPHIR3: | ||
423 | outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); | ||
424 | break; | ||
425 | case INF_QS1000: | ||
426 | outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); | ||
427 | break; | ||
428 | case INF_QS3000: | ||
429 | outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); | ||
430 | break; | ||
431 | case INF_NICCY: | ||
432 | val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); | ||
433 | val |= NICCY_IRQ_ENABLE;; | ||
434 | outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); | ||
435 | break; | ||
436 | case INF_SCT_1: | ||
437 | w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); | ||
438 | w |= SCT_PLX_IRQ_ENABLE; | ||
439 | outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); | ||
440 | break; | ||
441 | case INF_GAZEL_R685: | ||
442 | outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN, | ||
443 | (u32)hw->cfg.start + GAZEL_INCSR); | ||
444 | break; | ||
445 | case INF_GAZEL_R753: | ||
446 | outb(GAZEL_IPAC_EN + GAZEL_PCI_EN, | ||
447 | (u32)hw->cfg.start + GAZEL_INCSR); | ||
448 | break; | ||
449 | default: | ||
450 | break; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | static void | ||
455 | disable_hwirq(struct inf_hw *hw) | ||
456 | { | ||
457 | u16 w; | ||
458 | u32 val; | ||
459 | |||
460 | switch (hw->ci->typ) { | ||
461 | case INF_DIVA201: | ||
462 | case INF_DIVA202: | ||
463 | writel(0, hw->cfg.p); | ||
464 | break; | ||
465 | case INF_SPEEDWIN: | ||
466 | case INF_SAPHIR3: | ||
467 | outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); | ||
468 | break; | ||
469 | case INF_QS1000: | ||
470 | outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); | ||
471 | break; | ||
472 | case INF_QS3000: | ||
473 | outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); | ||
474 | break; | ||
475 | case INF_NICCY: | ||
476 | val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); | ||
477 | val &= NICCY_IRQ_DISABLE; | ||
478 | outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); | ||
479 | break; | ||
480 | case INF_SCT_1: | ||
481 | w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); | ||
482 | w &= (~SCT_PLX_IRQ_ENABLE); | ||
483 | outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); | ||
484 | break; | ||
485 | case INF_GAZEL_R685: | ||
486 | case INF_GAZEL_R753: | ||
487 | outb(0, (u32)hw->cfg.start + GAZEL_INCSR); | ||
488 | break; | ||
489 | default: | ||
490 | break; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | ipac_chip_reset(struct inf_hw *hw) | ||
496 | { | ||
497 | hw->ipac.write_reg(hw, IPAC_POTA2, 0x20); | ||
498 | mdelay(5); | ||
499 | hw->ipac.write_reg(hw, IPAC_POTA2, 0x00); | ||
500 | mdelay(5); | ||
501 | hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf); | ||
502 | hw->ipac.write_reg(hw, IPAC_MASK, 0xc0); | ||
503 | } | ||
504 | |||
505 | static void | ||
506 | reset_inf(struct inf_hw *hw) | ||
507 | { | ||
508 | u16 w; | ||
509 | u32 val; | ||
510 | |||
511 | if (debug & DEBUG_HW) | ||
512 | pr_notice("%s: resetting card\n", hw->name); | ||
513 | switch (hw->ci->typ) { | ||
514 | case INF_DIVA20: | ||
515 | case INF_DIVA20U: | ||
516 | outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL); | ||
517 | mdelay(10); | ||
518 | outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL); | ||
519 | mdelay(10); | ||
520 | /* Workaround PCI9060 */ | ||
521 | outb(9, (u32)hw->cfg.start + 0x69); | ||
522 | outb(DIVA_RESET_BIT | DIVA_LED_A, | ||
523 | (u32)hw->cfg.start + DIVA_PCI_CTRL); | ||
524 | break; | ||
525 | case INF_DIVA201: | ||
526 | writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, | ||
527 | hw->cfg.p + PITA_MISC_REG); | ||
528 | mdelay(1); | ||
529 | writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG); | ||
530 | mdelay(10); | ||
531 | break; | ||
532 | case INF_DIVA202: | ||
533 | writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, | ||
534 | hw->cfg.p + PITA_MISC_REG); | ||
535 | mdelay(1); | ||
536 | writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET, | ||
537 | hw->cfg.p + PITA_MISC_REG); | ||
538 | mdelay(10); | ||
539 | break; | ||
540 | case INF_SPEEDWIN: | ||
541 | case INF_SAPHIR3: | ||
542 | ipac_chip_reset(hw); | ||
543 | hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); | ||
544 | hw->ipac.write_reg(hw, IPAC_AOE, 0x00); | ||
545 | hw->ipac.write_reg(hw, IPAC_PCFG, 0x12); | ||
546 | break; | ||
547 | case INF_QS1000: | ||
548 | case INF_QS3000: | ||
549 | ipac_chip_reset(hw); | ||
550 | hw->ipac.write_reg(hw, IPAC_ACFG, 0x00); | ||
551 | hw->ipac.write_reg(hw, IPAC_AOE, 0x3c); | ||
552 | hw->ipac.write_reg(hw, IPAC_ATX, 0xff); | ||
553 | break; | ||
554 | case INF_NICCY: | ||
555 | break; | ||
556 | case INF_SCT_1: | ||
557 | w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); | ||
558 | w &= (~SCT_PLX_RESET_BIT); | ||
559 | outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); | ||
560 | mdelay(10); | ||
561 | w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); | ||
562 | w |= SCT_PLX_RESET_BIT; | ||
563 | outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); | ||
564 | mdelay(10); | ||
565 | break; | ||
566 | case INF_GAZEL_R685: | ||
567 | val = inl((u32)hw->cfg.start + GAZEL_CNTRL); | ||
568 | val |= (GAZEL_RESET_9050 + GAZEL_RESET); | ||
569 | outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); | ||
570 | val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); | ||
571 | mdelay(4); | ||
572 | outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); | ||
573 | mdelay(10); | ||
574 | hw->ipac.isac.adf2 = 0x87; | ||
575 | hw->ipac.hscx[0].slot = 0x1f; | ||
576 | hw->ipac.hscx[0].slot = 0x23; | ||
577 | break; | ||
578 | case INF_GAZEL_R753: | ||
579 | val = inl((u32)hw->cfg.start + GAZEL_CNTRL); | ||
580 | val |= (GAZEL_RESET_9050 + GAZEL_RESET); | ||
581 | outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); | ||
582 | val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); | ||
583 | mdelay(4); | ||
584 | outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); | ||
585 | mdelay(10); | ||
586 | ipac_chip_reset(hw); | ||
587 | hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); | ||
588 | hw->ipac.write_reg(hw, IPAC_AOE, 0x00); | ||
589 | hw->ipac.conf = 0x01; /* IOM off */ | ||
590 | break; | ||
591 | default: | ||
592 | return; | ||
593 | } | ||
594 | enable_hwirq(hw); | ||
595 | } | ||
596 | |||
597 | static int | ||
598 | inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg) | ||
599 | { | ||
600 | int ret = 0; | ||
601 | |||
602 | switch (cmd) { | ||
603 | case HW_RESET_REQ: | ||
604 | reset_inf(hw); | ||
605 | break; | ||
606 | default: | ||
607 | pr_info("%s: %s unknown command %x %lx\n", | ||
608 | hw->name, __func__, cmd, arg); | ||
609 | ret = -EINVAL; | ||
610 | break; | ||
611 | } | ||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | static int __devinit | ||
616 | init_irq(struct inf_hw *hw) | ||
617 | { | ||
618 | int ret, cnt = 3; | ||
619 | u_long flags; | ||
620 | |||
621 | if (!hw->ci->irqfunc) | ||
622 | return -EINVAL; | ||
623 | ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw); | ||
624 | if (ret) { | ||
625 | pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq); | ||
626 | return ret; | ||
627 | } | ||
628 | while (cnt--) { | ||
629 | spin_lock_irqsave(&hw->lock, flags); | ||
630 | reset_inf(hw); | ||
631 | ret = hw->ipac.init(&hw->ipac); | ||
632 | if (ret) { | ||
633 | spin_unlock_irqrestore(&hw->lock, flags); | ||
634 | pr_info("%s: ISAC init failed with %d\n", | ||
635 | hw->name, ret); | ||
636 | break; | ||
637 | } | ||
638 | spin_unlock_irqrestore(&hw->lock, flags); | ||
639 | msleep_interruptible(10); | ||
640 | if (debug & DEBUG_HW) | ||
641 | pr_notice("%s: IRQ %d count %d\n", hw->name, | ||
642 | hw->irq, hw->irqcnt); | ||
643 | if (!hw->irqcnt) { | ||
644 | pr_info("%s: IRQ(%d) got no requests during init %d\n", | ||
645 | hw->name, hw->irq, 3 - cnt); | ||
646 | } else | ||
647 | return 0; | ||
648 | } | ||
649 | free_irq(hw->irq, hw); | ||
650 | return -EIO; | ||
651 | } | ||
652 | |||
653 | static void | ||
654 | release_io(struct inf_hw *hw) | ||
655 | { | ||
656 | if (hw->cfg.mode) { | ||
657 | if (hw->cfg.p) { | ||
658 | release_mem_region(hw->cfg.start, hw->cfg.size); | ||
659 | iounmap(hw->cfg.p); | ||
660 | } else | ||
661 | release_region(hw->cfg.start, hw->cfg.size); | ||
662 | hw->cfg.mode = AM_NONE; | ||
663 | } | ||
664 | if (hw->addr.mode) { | ||
665 | if (hw->addr.p) { | ||
666 | release_mem_region(hw->addr.start, hw->addr.size); | ||
667 | iounmap(hw->addr.p); | ||
668 | } else | ||
669 | release_region(hw->addr.start, hw->addr.size); | ||
670 | hw->addr.mode = AM_NONE; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | static int __devinit | ||
675 | setup_io(struct inf_hw *hw) | ||
676 | { | ||
677 | int err = 0; | ||
678 | |||
679 | if (hw->ci->cfg_mode) { | ||
680 | hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar); | ||
681 | hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar); | ||
682 | if (hw->ci->cfg_mode == AM_MEMIO) { | ||
683 | if (!request_mem_region(hw->cfg.start, hw->cfg.size, | ||
684 | hw->name)) | ||
685 | err = -EBUSY; | ||
686 | } else { | ||
687 | if (!request_region(hw->cfg.start, hw->cfg.size, | ||
688 | hw->name)) | ||
689 | err = -EBUSY; | ||
690 | } | ||
691 | if (err) { | ||
692 | pr_info("mISDN: %s config port %lx (%lu bytes)" | ||
693 | "already in use\n", hw->name, | ||
694 | (ulong)hw->cfg.start, (ulong)hw->cfg.size); | ||
695 | return err; | ||
696 | } | ||
697 | if (hw->ci->cfg_mode == AM_MEMIO) | ||
698 | hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size); | ||
699 | hw->cfg.mode = hw->ci->cfg_mode; | ||
700 | if (debug & DEBUG_HW) | ||
701 | pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n", | ||
702 | hw->name, (ulong)hw->cfg.start, | ||
703 | (ulong)hw->cfg.size, hw->ci->cfg_mode); | ||
704 | |||
705 | } | ||
706 | if (hw->ci->addr_mode) { | ||
707 | hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar); | ||
708 | hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar); | ||
709 | if (hw->ci->addr_mode == AM_MEMIO) { | ||
710 | if (!request_mem_region(hw->addr.start, hw->addr.size, | ||
711 | hw->name)) | ||
712 | err = -EBUSY; | ||
713 | } else { | ||
714 | if (!request_region(hw->addr.start, hw->addr.size, | ||
715 | hw->name)) | ||
716 | err = -EBUSY; | ||
717 | } | ||
718 | if (err) { | ||
719 | pr_info("mISDN: %s address port %lx (%lu bytes)" | ||
720 | "already in use\n", hw->name, | ||
721 | (ulong)hw->addr.start, (ulong)hw->addr.size); | ||
722 | return err; | ||
723 | } | ||
724 | if (hw->ci->addr_mode == AM_MEMIO) | ||
725 | hw->addr.p = ioremap(hw->addr.start, hw->addr.size); | ||
726 | hw->addr.mode = hw->ci->addr_mode; | ||
727 | if (debug & DEBUG_HW) | ||
728 | pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n", | ||
729 | hw->name, (ulong)hw->addr.start, | ||
730 | (ulong)hw->addr.size, hw->ci->addr_mode); | ||
731 | |||
732 | } | ||
733 | |||
734 | switch (hw->ci->typ) { | ||
735 | case INF_DIVA20: | ||
736 | case INF_DIVA20U: | ||
737 | hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; | ||
738 | hw->isac.mode = hw->cfg.mode; | ||
739 | hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE; | ||
740 | hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT; | ||
741 | hw->hscx.mode = hw->cfg.mode; | ||
742 | hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE; | ||
743 | hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT; | ||
744 | break; | ||
745 | case INF_DIVA201: | ||
746 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
747 | hw->ipac.isac.off = 0x80; | ||
748 | hw->isac.mode = hw->addr.mode; | ||
749 | hw->isac.a.p = hw->addr.p; | ||
750 | hw->hscx.mode = hw->addr.mode; | ||
751 | hw->hscx.a.p = hw->addr.p; | ||
752 | break; | ||
753 | case INF_DIVA202: | ||
754 | hw->ipac.type = IPAC_TYPE_IPACX; | ||
755 | hw->isac.mode = hw->addr.mode; | ||
756 | hw->isac.a.p = hw->addr.p; | ||
757 | hw->hscx.mode = hw->addr.mode; | ||
758 | hw->hscx.a.p = hw->addr.p; | ||
759 | break; | ||
760 | case INF_SPEEDWIN: | ||
761 | case INF_SAPHIR3: | ||
762 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
763 | hw->ipac.isac.off = 0x80; | ||
764 | hw->isac.mode = hw->cfg.mode; | ||
765 | hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; | ||
766 | hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; | ||
767 | hw->hscx.mode = hw->cfg.mode; | ||
768 | hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; | ||
769 | hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; | ||
770 | outb(0xff, (ulong)hw->cfg.start); | ||
771 | mdelay(1); | ||
772 | outb(0x00, (ulong)hw->cfg.start); | ||
773 | mdelay(1); | ||
774 | outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL); | ||
775 | break; | ||
776 | case INF_QS1000: | ||
777 | case INF_QS3000: | ||
778 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
779 | hw->ipac.isac.off = 0x80; | ||
780 | hw->isac.a.io.ale = (u32)hw->addr.start; | ||
781 | hw->isac.a.io.port = (u32)hw->addr.start + 1; | ||
782 | hw->isac.mode = hw->addr.mode; | ||
783 | hw->hscx.a.io.ale = (u32)hw->addr.start; | ||
784 | hw->hscx.a.io.port = (u32)hw->addr.start + 1; | ||
785 | hw->hscx.mode = hw->addr.mode; | ||
786 | break; | ||
787 | case INF_NICCY: | ||
788 | hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; | ||
789 | hw->isac.mode = hw->addr.mode; | ||
790 | hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE; | ||
791 | hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT; | ||
792 | hw->hscx.mode = hw->addr.mode; | ||
793 | hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE; | ||
794 | hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT; | ||
795 | break; | ||
796 | case INF_SCT_1: | ||
797 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
798 | hw->ipac.isac.off = 0x80; | ||
799 | hw->isac.a.io.ale = (u32)hw->addr.start; | ||
800 | hw->isac.a.io.port = hw->isac.a.io.ale + 4; | ||
801 | hw->isac.mode = hw->addr.mode; | ||
802 | hw->hscx.a.io.ale = hw->isac.a.io.ale; | ||
803 | hw->hscx.a.io.port = hw->isac.a.io.port; | ||
804 | hw->hscx.mode = hw->addr.mode; | ||
805 | break; | ||
806 | case INF_SCT_2: | ||
807 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
808 | hw->ipac.isac.off = 0x80; | ||
809 | hw->isac.a.io.ale = (u32)hw->addr.start + 0x08; | ||
810 | hw->isac.a.io.port = hw->isac.a.io.ale + 4; | ||
811 | hw->isac.mode = hw->addr.mode; | ||
812 | hw->hscx.a.io.ale = hw->isac.a.io.ale; | ||
813 | hw->hscx.a.io.port = hw->isac.a.io.port; | ||
814 | hw->hscx.mode = hw->addr.mode; | ||
815 | break; | ||
816 | case INF_SCT_3: | ||
817 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
818 | hw->ipac.isac.off = 0x80; | ||
819 | hw->isac.a.io.ale = (u32)hw->addr.start + 0x10; | ||
820 | hw->isac.a.io.port = hw->isac.a.io.ale + 4; | ||
821 | hw->isac.mode = hw->addr.mode; | ||
822 | hw->hscx.a.io.ale = hw->isac.a.io.ale; | ||
823 | hw->hscx.a.io.port = hw->isac.a.io.port; | ||
824 | hw->hscx.mode = hw->addr.mode; | ||
825 | break; | ||
826 | case INF_SCT_4: | ||
827 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
828 | hw->ipac.isac.off = 0x80; | ||
829 | hw->isac.a.io.ale = (u32)hw->addr.start + 0x20; | ||
830 | hw->isac.a.io.port = hw->isac.a.io.ale + 4; | ||
831 | hw->isac.mode = hw->addr.mode; | ||
832 | hw->hscx.a.io.ale = hw->isac.a.io.ale; | ||
833 | hw->hscx.a.io.port = hw->isac.a.io.port; | ||
834 | hw->hscx.mode = hw->addr.mode; | ||
835 | break; | ||
836 | case INF_GAZEL_R685: | ||
837 | hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; | ||
838 | hw->ipac.isac.off = 0x80; | ||
839 | hw->isac.mode = hw->addr.mode; | ||
840 | hw->isac.a.io.port = (u32)hw->addr.start; | ||
841 | hw->hscx.mode = hw->addr.mode; | ||
842 | hw->hscx.a.io.port = hw->isac.a.io.port; | ||
843 | break; | ||
844 | case INF_GAZEL_R753: | ||
845 | hw->ipac.type = IPAC_TYPE_IPAC; | ||
846 | hw->ipac.isac.off = 0x80; | ||
847 | hw->isac.mode = hw->addr.mode; | ||
848 | hw->isac.a.io.ale = (u32)hw->addr.start; | ||
849 | hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT; | ||
850 | hw->hscx.mode = hw->addr.mode; | ||
851 | hw->hscx.a.io.ale = hw->isac.a.io.ale; | ||
852 | hw->hscx.a.io.port = hw->isac.a.io.port; | ||
853 | break; | ||
854 | default: | ||
855 | return -EINVAL; | ||
856 | } | ||
857 | switch (hw->isac.mode) { | ||
858 | case AM_MEMIO: | ||
859 | ASSIGN_FUNC_IPAC(MIO, hw->ipac); | ||
860 | break; | ||
861 | case AM_IND_IO: | ||
862 | ASSIGN_FUNC_IPAC(IND, hw->ipac); | ||
863 | break; | ||
864 | case AM_IO: | ||
865 | ASSIGN_FUNC_IPAC(IO, hw->ipac); | ||
866 | break; | ||
867 | default: | ||
868 | return -EINVAL; | ||
869 | } | ||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | static void | ||
874 | release_card(struct inf_hw *card) { | ||
875 | ulong flags; | ||
876 | int i; | ||
877 | |||
878 | spin_lock_irqsave(&card->lock, flags); | ||
879 | disable_hwirq(card); | ||
880 | spin_unlock_irqrestore(&card->lock, flags); | ||
881 | card->ipac.isac.release(&card->ipac.isac); | ||
882 | free_irq(card->irq, card); | ||
883 | mISDN_unregister_device(&card->ipac.isac.dch.dev); | ||
884 | release_io(card); | ||
885 | write_lock_irqsave(&card_lock, flags); | ||
886 | list_del(&card->list); | ||
887 | write_unlock_irqrestore(&card_lock, flags); | ||
888 | switch (card->ci->typ) { | ||
889 | case INF_SCT_2: | ||
890 | case INF_SCT_3: | ||
891 | case INF_SCT_4: | ||
892 | break; | ||
893 | case INF_SCT_1: | ||
894 | for (i = 0; i < 3; i++) { | ||
895 | if (card->sc[i]) | ||
896 | release_card(card->sc[i]); | ||
897 | card->sc[i] = NULL; | ||
898 | } | ||
899 | default: | ||
900 | pci_disable_device(card->pdev); | ||
901 | pci_set_drvdata(card->pdev, NULL); | ||
902 | break; | ||
903 | } | ||
904 | kfree(card); | ||
905 | inf_cnt--; | ||
906 | } | ||
907 | |||
908 | static int __devinit | ||
909 | setup_instance(struct inf_hw *card) | ||
910 | { | ||
911 | int err; | ||
912 | ulong flags; | ||
913 | |||
914 | snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name, | ||
915 | inf_cnt + 1); | ||
916 | write_lock_irqsave(&card_lock, flags); | ||
917 | list_add_tail(&card->list, &Cards); | ||
918 | write_unlock_irqrestore(&card_lock, flags); | ||
919 | |||
920 | _set_debug(card); | ||
921 | card->ipac.isac.name = card->name; | ||
922 | card->ipac.name = card->name; | ||
923 | card->ipac.owner = THIS_MODULE; | ||
924 | spin_lock_init(&card->lock); | ||
925 | card->ipac.isac.hwlock = &card->lock; | ||
926 | card->ipac.hwlock = &card->lock; | ||
927 | card->ipac.ctrl = (void *)&inf_ctrl; | ||
928 | |||
929 | err = setup_io(card); | ||
930 | if (err) | ||
931 | goto error_setup; | ||
932 | |||
933 | card->ipac.isac.dch.dev.Bprotocols = | ||
934 | mISDNipac_init(&card->ipac, card); | ||
935 | |||
936 | if (card->ipac.isac.dch.dev.Bprotocols == 0) | ||
937 | goto error_setup;; | ||
938 | |||
939 | err = mISDN_register_device(&card->ipac.isac.dch.dev, | ||
940 | &card->pdev->dev, card->name); | ||
941 | if (err) | ||
942 | goto error; | ||
943 | |||
944 | err = init_irq(card); | ||
945 | if (!err) { | ||
946 | inf_cnt++; | ||
947 | pr_notice("Infineon %d cards installed\n", inf_cnt); | ||
948 | return 0; | ||
949 | } | ||
950 | mISDN_unregister_device(&card->ipac.isac.dch.dev); | ||
951 | error: | ||
952 | card->ipac.release(&card->ipac); | ||
953 | error_setup: | ||
954 | release_io(card); | ||
955 | write_lock_irqsave(&card_lock, flags); | ||
956 | list_del(&card->list); | ||
957 | write_unlock_irqrestore(&card_lock, flags); | ||
958 | return err; | ||
959 | } | ||
960 | |||
961 | static const struct inf_cinfo inf_card_info[] = { | ||
962 | { | ||
963 | INF_DIVA20, | ||
964 | "Dialogic Diva 2.0", | ||
965 | "diva20", | ||
966 | AM_IND_IO, AM_NONE, 2, 0, | ||
967 | &diva_irq | ||
968 | }, | ||
969 | { | ||
970 | INF_DIVA20U, | ||
971 | "Dialogic Diva 2.0U", | ||
972 | "diva20U", | ||
973 | AM_IND_IO, AM_NONE, 2, 0, | ||
974 | &diva_irq | ||
975 | }, | ||
976 | { | ||
977 | INF_DIVA201, | ||
978 | "Dialogic Diva 2.01", | ||
979 | "diva201", | ||
980 | AM_MEMIO, AM_MEMIO, 0, 1, | ||
981 | &diva20x_irq | ||
982 | }, | ||
983 | { | ||
984 | INF_DIVA202, | ||
985 | "Dialogic Diva 2.02", | ||
986 | "diva202", | ||
987 | AM_MEMIO, AM_MEMIO, 0, 1, | ||
988 | &diva20x_irq | ||
989 | }, | ||
990 | { | ||
991 | INF_SPEEDWIN, | ||
992 | "Sedlbauer SpeedWin PCI", | ||
993 | "speedwin", | ||
994 | AM_IND_IO, AM_NONE, 0, 0, | ||
995 | &tiger_irq | ||
996 | }, | ||
997 | { | ||
998 | INF_SAPHIR3, | ||
999 | "HST Saphir 3", | ||
1000 | "saphir", | ||
1001 | AM_IND_IO, AM_NONE, 0, 0, | ||
1002 | &tiger_irq | ||
1003 | }, | ||
1004 | { | ||
1005 | INF_QS1000, | ||
1006 | "Develo Microlink PCI", | ||
1007 | "qs1000", | ||
1008 | AM_IO, AM_IND_IO, 1, 3, | ||
1009 | &elsa_irq | ||
1010 | }, | ||
1011 | { | ||
1012 | INF_QS3000, | ||
1013 | "Develo QuickStep 3000", | ||
1014 | "qs3000", | ||
1015 | AM_IO, AM_IND_IO, 1, 3, | ||
1016 | &elsa_irq | ||
1017 | }, | ||
1018 | { | ||
1019 | INF_NICCY, | ||
1020 | "Sagem NICCY", | ||
1021 | "niccy", | ||
1022 | AM_IO, AM_IND_IO, 0, 1, | ||
1023 | &niccy_irq | ||
1024 | }, | ||
1025 | { | ||
1026 | INF_SCT_1, | ||
1027 | "SciTel Quadro", | ||
1028 | "p1_scitel", | ||
1029 | AM_IO, AM_IND_IO, 1, 5, | ||
1030 | &ipac_irq | ||
1031 | }, | ||
1032 | { | ||
1033 | INF_SCT_2, | ||
1034 | "SciTel Quadro", | ||
1035 | "p2_scitel", | ||
1036 | AM_NONE, AM_IND_IO, 0, 4, | ||
1037 | &ipac_irq | ||
1038 | }, | ||
1039 | { | ||
1040 | INF_SCT_3, | ||
1041 | "SciTel Quadro", | ||
1042 | "p3_scitel", | ||
1043 | AM_NONE, AM_IND_IO, 0, 3, | ||
1044 | &ipac_irq | ||
1045 | }, | ||
1046 | { | ||
1047 | INF_SCT_4, | ||
1048 | "SciTel Quadro", | ||
1049 | "p4_scitel", | ||
1050 | AM_NONE, AM_IND_IO, 0, 2, | ||
1051 | &ipac_irq | ||
1052 | }, | ||
1053 | { | ||
1054 | INF_GAZEL_R685, | ||
1055 | "Gazel R685", | ||
1056 | "gazel685", | ||
1057 | AM_IO, AM_IO, 1, 2, | ||
1058 | &gazel_irq | ||
1059 | }, | ||
1060 | { | ||
1061 | INF_GAZEL_R753, | ||
1062 | "Gazel R753", | ||
1063 | "gazel753", | ||
1064 | AM_IO, AM_IND_IO, 1, 2, | ||
1065 | &ipac_irq | ||
1066 | }, | ||
1067 | { | ||
1068 | INF_NONE, | ||
1069 | } | ||
1070 | }; | ||
1071 | |||
1072 | static const struct inf_cinfo * __devinit | ||
1073 | get_card_info(enum inf_types typ) | ||
1074 | { | ||
1075 | const struct inf_cinfo *ci = inf_card_info; | ||
1076 | |||
1077 | while (ci->typ != INF_NONE) { | ||
1078 | if (ci->typ == typ) | ||
1079 | return ci; | ||
1080 | ci++; | ||
1081 | } | ||
1082 | return NULL; | ||
1083 | } | ||
1084 | |||
1085 | static int __devinit | ||
1086 | inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
1087 | { | ||
1088 | int err = -ENOMEM; | ||
1089 | struct inf_hw *card; | ||
1090 | |||
1091 | card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL); | ||
1092 | if (!card) { | ||
1093 | pr_info("No memory for Infineon ISDN card\n"); | ||
1094 | return err; | ||
1095 | } | ||
1096 | card->pdev = pdev; | ||
1097 | err = pci_enable_device(pdev); | ||
1098 | if (err) { | ||
1099 | kfree(card); | ||
1100 | return err; | ||
1101 | } | ||
1102 | card->ci = get_card_info(ent->driver_data); | ||
1103 | if (!card->ci) { | ||
1104 | pr_info("mISDN: do not have informations about adapter at %s\n", | ||
1105 | pci_name(pdev)); | ||
1106 | kfree(card); | ||
1107 | return -EINVAL; | ||
1108 | } else | ||
1109 | pr_notice("mISDN: found adapter %s at %s\n", | ||
1110 | card->ci->full, pci_name(pdev)); | ||
1111 | |||
1112 | card->irq = pdev->irq; | ||
1113 | pci_set_drvdata(pdev, card); | ||
1114 | err = setup_instance(card); | ||
1115 | if (err) { | ||
1116 | pci_disable_device(card->pdev); | ||
1117 | kfree(card); | ||
1118 | pci_set_drvdata(pdev, NULL); | ||
1119 | } else if (ent->driver_data == INF_SCT_1) { | ||
1120 | int i; | ||
1121 | struct inf_hw *sc; | ||
1122 | |||
1123 | for (i = 1; i < 4; i++) { | ||
1124 | sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL); | ||
1125 | if (!sc) { | ||
1126 | release_card(card); | ||
1127 | return -ENOMEM; | ||
1128 | } | ||
1129 | sc->irq = card->irq; | ||
1130 | sc->pdev = card->pdev; | ||
1131 | sc->ci = card->ci + i; | ||
1132 | err = setup_instance(sc); | ||
1133 | if (err) { | ||
1134 | kfree(sc); | ||
1135 | release_card(card); | ||
1136 | } else | ||
1137 | card->sc[i - 1] = sc; | ||
1138 | } | ||
1139 | } | ||
1140 | return err; | ||
1141 | } | ||
1142 | |||
1143 | static void __devexit | ||
1144 | inf_remove(struct pci_dev *pdev) | ||
1145 | { | ||
1146 | struct inf_hw *card = pci_get_drvdata(pdev); | ||
1147 | |||
1148 | if (card) | ||
1149 | release_card(card); | ||
1150 | else | ||
1151 | pr_debug("%s: drvdata allready removed\n", __func__); | ||
1152 | } | ||
1153 | |||
1154 | static struct pci_driver infineon_driver = { | ||
1155 | .name = "ISDN Infineon pci", | ||
1156 | .probe = inf_probe, | ||
1157 | .remove = __devexit_p(inf_remove), | ||
1158 | .id_table = infineon_ids, | ||
1159 | }; | ||
1160 | |||
1161 | static int __init | ||
1162 | infineon_init(void) | ||
1163 | { | ||
1164 | int err; | ||
1165 | |||
1166 | pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV); | ||
1167 | err = pci_register_driver(&infineon_driver); | ||
1168 | return err; | ||
1169 | } | ||
1170 | |||
1171 | static void __exit | ||
1172 | infineon_cleanup(void) | ||
1173 | { | ||
1174 | pci_unregister_driver(&infineon_driver); | ||
1175 | } | ||
1176 | |||
1177 | module_init(infineon_init); | ||
1178 | module_exit(infineon_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c new file mode 100644 index 000000000000..613ba0435372 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c | |||
@@ -0,0 +1,1655 @@ | |||
1 | /* | ||
2 | * isac.c ISAC specific routines | ||
3 | * | ||
4 | * Author Karsten Keil <keil@isdn4linux.de> | ||
5 | * | ||
6 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/mISDNhw.h> | ||
25 | #include "ipac.h" | ||
26 | |||
27 | |||
28 | #define DBUSY_TIMER_VALUE 80 | ||
29 | #define ARCOFI_USE 1 | ||
30 | |||
31 | #define ISAC_REV "2.0" | ||
32 | |||
33 | MODULE_AUTHOR("Karsten Keil"); | ||
34 | MODULE_VERSION(ISAC_REV); | ||
35 | MODULE_LICENSE("GPL v2"); | ||
36 | |||
37 | #define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off)) | ||
38 | #define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v)) | ||
39 | #define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o)) | ||
40 | #define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v)) | ||
41 | #define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o)) | ||
42 | #define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v)) | ||
43 | |||
44 | static inline void | ||
45 | ph_command(struct isac_hw *isac, u8 command) | ||
46 | { | ||
47 | pr_debug("%s: ph_command %x\n", isac->name, command); | ||
48 | if (isac->type & IPAC_TYPE_ISACX) | ||
49 | WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE); | ||
50 | else | ||
51 | WriteISAC(isac, ISAC_CIX0, (command << 2) | 3); | ||
52 | } | ||
53 | |||
54 | static void | ||
55 | isac_ph_state_change(struct isac_hw *isac) | ||
56 | { | ||
57 | switch (isac->state) { | ||
58 | case (ISAC_IND_RS): | ||
59 | case (ISAC_IND_EI): | ||
60 | ph_command(isac, ISAC_CMD_DUI); | ||
61 | } | ||
62 | schedule_event(&isac->dch, FLG_PHCHANGE); | ||
63 | } | ||
64 | |||
65 | static void | ||
66 | isac_ph_state_bh(struct dchannel *dch) | ||
67 | { | ||
68 | struct isac_hw *isac = container_of(dch, struct isac_hw, dch); | ||
69 | |||
70 | switch (isac->state) { | ||
71 | case ISAC_IND_RS: | ||
72 | case ISAC_IND_EI: | ||
73 | dch->state = 0; | ||
74 | l1_event(dch->l1, HW_RESET_IND); | ||
75 | break; | ||
76 | case ISAC_IND_DID: | ||
77 | dch->state = 3; | ||
78 | l1_event(dch->l1, HW_DEACT_CNF); | ||
79 | break; | ||
80 | case ISAC_IND_DR: | ||
81 | dch->state = 3; | ||
82 | l1_event(dch->l1, HW_DEACT_IND); | ||
83 | break; | ||
84 | case ISAC_IND_PU: | ||
85 | dch->state = 4; | ||
86 | l1_event(dch->l1, HW_POWERUP_IND); | ||
87 | break; | ||
88 | case ISAC_IND_RSY: | ||
89 | if (dch->state <= 5) { | ||
90 | dch->state = 5; | ||
91 | l1_event(dch->l1, ANYSIGNAL); | ||
92 | } else { | ||
93 | dch->state = 8; | ||
94 | l1_event(dch->l1, LOSTFRAMING); | ||
95 | } | ||
96 | break; | ||
97 | case ISAC_IND_ARD: | ||
98 | dch->state = 6; | ||
99 | l1_event(dch->l1, INFO2); | ||
100 | break; | ||
101 | case ISAC_IND_AI8: | ||
102 | dch->state = 7; | ||
103 | l1_event(dch->l1, INFO4_P8); | ||
104 | break; | ||
105 | case ISAC_IND_AI10: | ||
106 | dch->state = 7; | ||
107 | l1_event(dch->l1, INFO4_P10); | ||
108 | break; | ||
109 | } | ||
110 | pr_debug("%s: TE newstate %x\n", isac->name, dch->state); | ||
111 | } | ||
112 | |||
113 | void | ||
114 | isac_empty_fifo(struct isac_hw *isac, int count) | ||
115 | { | ||
116 | u8 *ptr; | ||
117 | |||
118 | pr_debug("%s: %s %d\n", isac->name, __func__, count); | ||
119 | |||
120 | if (!isac->dch.rx_skb) { | ||
121 | isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC); | ||
122 | if (!isac->dch.rx_skb) { | ||
123 | pr_info("%s: D receive out of memory\n", isac->name); | ||
124 | WriteISAC(isac, ISAC_CMDR, 0x80); | ||
125 | return; | ||
126 | } | ||
127 | } | ||
128 | if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) { | ||
129 | pr_debug("%s: %s overrun %d\n", isac->name, __func__, | ||
130 | isac->dch.rx_skb->len + count); | ||
131 | WriteISAC(isac, ISAC_CMDR, 0x80); | ||
132 | return; | ||
133 | } | ||
134 | ptr = skb_put(isac->dch.rx_skb, count); | ||
135 | isac->read_fifo(isac->dch.hw, isac->off, ptr, count); | ||
136 | WriteISAC(isac, ISAC_CMDR, 0x80); | ||
137 | if (isac->dch.debug & DEBUG_HW_DFIFO) { | ||
138 | char pfx[MISDN_MAX_IDLEN + 16]; | ||
139 | |||
140 | snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ", | ||
141 | isac->name, count); | ||
142 | print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static void | ||
147 | isac_fill_fifo(struct isac_hw *isac) | ||
148 | { | ||
149 | int count, more; | ||
150 | u8 *ptr; | ||
151 | |||
152 | if (!isac->dch.tx_skb) | ||
153 | return; | ||
154 | count = isac->dch.tx_skb->len - isac->dch.tx_idx; | ||
155 | if (count <= 0) | ||
156 | return; | ||
157 | |||
158 | more = 0; | ||
159 | if (count > 32) { | ||
160 | more = !0; | ||
161 | count = 32; | ||
162 | } | ||
163 | pr_debug("%s: %s %d\n", isac->name, __func__, count); | ||
164 | ptr = isac->dch.tx_skb->data + isac->dch.tx_idx; | ||
165 | isac->dch.tx_idx += count; | ||
166 | isac->write_fifo(isac->dch.hw, isac->off, ptr, count); | ||
167 | WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa); | ||
168 | if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { | ||
169 | pr_debug("%s: %s dbusytimer running\n", isac->name, __func__); | ||
170 | del_timer(&isac->dch.timer); | ||
171 | } | ||
172 | init_timer(&isac->dch.timer); | ||
173 | isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); | ||
174 | add_timer(&isac->dch.timer); | ||
175 | if (isac->dch.debug & DEBUG_HW_DFIFO) { | ||
176 | char pfx[MISDN_MAX_IDLEN + 16]; | ||
177 | |||
178 | snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ", | ||
179 | isac->name, count); | ||
180 | print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static void | ||
185 | isac_rme_irq(struct isac_hw *isac) | ||
186 | { | ||
187 | u8 val, count; | ||
188 | |||
189 | val = ReadISAC(isac, ISAC_RSTA); | ||
190 | if ((val & 0x70) != 0x20) { | ||
191 | if (val & 0x40) { | ||
192 | pr_debug("%s: ISAC RDO\n", isac->name); | ||
193 | #ifdef ERROR_STATISTIC | ||
194 | isac->dch.err_rx++; | ||
195 | #endif | ||
196 | } | ||
197 | if (!(val & 0x20)) { | ||
198 | pr_debug("%s: ISAC CRC error\n", isac->name); | ||
199 | #ifdef ERROR_STATISTIC | ||
200 | isac->dch.err_crc++; | ||
201 | #endif | ||
202 | } | ||
203 | WriteISAC(isac, ISAC_CMDR, 0x80); | ||
204 | if (isac->dch.rx_skb) | ||
205 | dev_kfree_skb(isac->dch.rx_skb); | ||
206 | isac->dch.rx_skb = NULL; | ||
207 | } else { | ||
208 | count = ReadISAC(isac, ISAC_RBCL) & 0x1f; | ||
209 | if (count == 0) | ||
210 | count = 32; | ||
211 | isac_empty_fifo(isac, count); | ||
212 | recv_Dchannel(&isac->dch); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void | ||
217 | isac_xpr_irq(struct isac_hw *isac) | ||
218 | { | ||
219 | if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) | ||
220 | del_timer(&isac->dch.timer); | ||
221 | if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) { | ||
222 | isac_fill_fifo(isac); | ||
223 | } else { | ||
224 | if (isac->dch.tx_skb) | ||
225 | dev_kfree_skb(isac->dch.tx_skb); | ||
226 | if (get_next_dframe(&isac->dch)) | ||
227 | isac_fill_fifo(isac); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static void | ||
232 | isac_retransmit(struct isac_hw *isac) | ||
233 | { | ||
234 | if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) | ||
235 | del_timer(&isac->dch.timer); | ||
236 | if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) { | ||
237 | /* Restart frame */ | ||
238 | isac->dch.tx_idx = 0; | ||
239 | isac_fill_fifo(isac); | ||
240 | } else if (isac->dch.tx_skb) { /* should not happen */ | ||
241 | pr_info("%s: tx_skb exist but not busy\n", isac->name); | ||
242 | test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags); | ||
243 | isac->dch.tx_idx = 0; | ||
244 | isac_fill_fifo(isac); | ||
245 | } else { | ||
246 | pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name); | ||
247 | if (get_next_dframe(&isac->dch)) | ||
248 | isac_fill_fifo(isac); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | static void | ||
253 | isac_mos_irq(struct isac_hw *isac) | ||
254 | { | ||
255 | u8 val; | ||
256 | int ret; | ||
257 | |||
258 | val = ReadISAC(isac, ISAC_MOSR); | ||
259 | pr_debug("%s: ISAC MOSR %02x\n", isac->name, val); | ||
260 | #if ARCOFI_USE | ||
261 | if (val & 0x08) { | ||
262 | if (!isac->mon_rx) { | ||
263 | isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); | ||
264 | if (!isac->mon_rx) { | ||
265 | pr_info("%s: ISAC MON RX out of memory!\n", | ||
266 | isac->name); | ||
267 | isac->mocr &= 0xf0; | ||
268 | isac->mocr |= 0x0a; | ||
269 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
270 | goto afterMONR0; | ||
271 | } else | ||
272 | isac->mon_rxp = 0; | ||
273 | } | ||
274 | if (isac->mon_rxp >= MAX_MON_FRAME) { | ||
275 | isac->mocr &= 0xf0; | ||
276 | isac->mocr |= 0x0a; | ||
277 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
278 | isac->mon_rxp = 0; | ||
279 | pr_debug("%s: ISAC MON RX overflow!\n", isac->name); | ||
280 | goto afterMONR0; | ||
281 | } | ||
282 | isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0); | ||
283 | pr_debug("%s: ISAC MOR0 %02x\n", isac->name, | ||
284 | isac->mon_rx[isac->mon_rxp - 1]); | ||
285 | if (isac->mon_rxp == 1) { | ||
286 | isac->mocr |= 0x04; | ||
287 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
288 | } | ||
289 | } | ||
290 | afterMONR0: | ||
291 | if (val & 0x80) { | ||
292 | if (!isac->mon_rx) { | ||
293 | isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); | ||
294 | if (!isac->mon_rx) { | ||
295 | pr_info("%s: ISAC MON RX out of memory!\n", | ||
296 | isac->name); | ||
297 | isac->mocr &= 0x0f; | ||
298 | isac->mocr |= 0xa0; | ||
299 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
300 | goto afterMONR1; | ||
301 | } else | ||
302 | isac->mon_rxp = 0; | ||
303 | } | ||
304 | if (isac->mon_rxp >= MAX_MON_FRAME) { | ||
305 | isac->mocr &= 0x0f; | ||
306 | isac->mocr |= 0xa0; | ||
307 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
308 | isac->mon_rxp = 0; | ||
309 | pr_debug("%s: ISAC MON RX overflow!\n", isac->name); | ||
310 | goto afterMONR1; | ||
311 | } | ||
312 | isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1); | ||
313 | pr_debug("%s: ISAC MOR1 %02x\n", isac->name, | ||
314 | isac->mon_rx[isac->mon_rxp - 1]); | ||
315 | isac->mocr |= 0x40; | ||
316 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
317 | } | ||
318 | afterMONR1: | ||
319 | if (val & 0x04) { | ||
320 | isac->mocr &= 0xf0; | ||
321 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
322 | isac->mocr |= 0x0a; | ||
323 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
324 | if (isac->monitor) { | ||
325 | ret = isac->monitor(isac->dch.hw, MONITOR_RX_0, | ||
326 | isac->mon_rx, isac->mon_rxp); | ||
327 | if (ret) | ||
328 | kfree(isac->mon_rx); | ||
329 | } else { | ||
330 | pr_info("%s: MONITOR 0 received %d but no user\n", | ||
331 | isac->name, isac->mon_rxp); | ||
332 | kfree(isac->mon_rx); | ||
333 | } | ||
334 | isac->mon_rx = NULL; | ||
335 | isac->mon_rxp = 0; | ||
336 | } | ||
337 | if (val & 0x40) { | ||
338 | isac->mocr &= 0x0f; | ||
339 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
340 | isac->mocr |= 0xa0; | ||
341 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
342 | if (isac->monitor) { | ||
343 | ret = isac->monitor(isac->dch.hw, MONITOR_RX_1, | ||
344 | isac->mon_rx, isac->mon_rxp); | ||
345 | if (ret) | ||
346 | kfree(isac->mon_rx); | ||
347 | } else { | ||
348 | pr_info("%s: MONITOR 1 received %d but no user\n", | ||
349 | isac->name, isac->mon_rxp); | ||
350 | kfree(isac->mon_rx); | ||
351 | } | ||
352 | isac->mon_rx = NULL; | ||
353 | isac->mon_rxp = 0; | ||
354 | } | ||
355 | if (val & 0x02) { | ||
356 | if ((!isac->mon_tx) || (isac->mon_txc && | ||
357 | (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) { | ||
358 | isac->mocr &= 0xf0; | ||
359 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
360 | isac->mocr |= 0x0a; | ||
361 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
362 | if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { | ||
363 | if (isac->monitor) | ||
364 | ret = isac->monitor(isac->dch.hw, | ||
365 | MONITOR_TX_0, NULL, 0); | ||
366 | } | ||
367 | kfree(isac->mon_tx); | ||
368 | isac->mon_tx = NULL; | ||
369 | isac->mon_txc = 0; | ||
370 | isac->mon_txp = 0; | ||
371 | goto AfterMOX0; | ||
372 | } | ||
373 | if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { | ||
374 | if (isac->monitor) | ||
375 | ret = isac->monitor(isac->dch.hw, | ||
376 | MONITOR_TX_0, NULL, 0); | ||
377 | kfree(isac->mon_tx); | ||
378 | isac->mon_tx = NULL; | ||
379 | isac->mon_txc = 0; | ||
380 | isac->mon_txp = 0; | ||
381 | goto AfterMOX0; | ||
382 | } | ||
383 | WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]); | ||
384 | pr_debug("%s: ISAC %02x -> MOX0\n", isac->name, | ||
385 | isac->mon_tx[isac->mon_txp - 1]); | ||
386 | } | ||
387 | AfterMOX0: | ||
388 | if (val & 0x20) { | ||
389 | if ((!isac->mon_tx) || (isac->mon_txc && | ||
390 | (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) { | ||
391 | isac->mocr &= 0x0f; | ||
392 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
393 | isac->mocr |= 0xa0; | ||
394 | WriteISAC(isac, ISAC_MOCR, isac->mocr); | ||
395 | if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { | ||
396 | if (isac->monitor) | ||
397 | ret = isac->monitor(isac->dch.hw, | ||
398 | MONITOR_TX_1, NULL, 0); | ||
399 | } | ||
400 | kfree(isac->mon_tx); | ||
401 | isac->mon_tx = NULL; | ||
402 | isac->mon_txc = 0; | ||
403 | isac->mon_txp = 0; | ||
404 | goto AfterMOX1; | ||
405 | } | ||
406 | if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { | ||
407 | if (isac->monitor) | ||
408 | ret = isac->monitor(isac->dch.hw, | ||
409 | MONITOR_TX_1, NULL, 0); | ||
410 | kfree(isac->mon_tx); | ||
411 | isac->mon_tx = NULL; | ||
412 | isac->mon_txc = 0; | ||
413 | isac->mon_txp = 0; | ||
414 | goto AfterMOX1; | ||
415 | } | ||
416 | WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]); | ||
417 | pr_debug("%s: ISAC %02x -> MOX1\n", isac->name, | ||
418 | isac->mon_tx[isac->mon_txp - 1]); | ||
419 | } | ||
420 | AfterMOX1: | ||
421 | val = 0; /* dummy to avoid warning */ | ||
422 | #endif | ||
423 | } | ||
424 | |||
425 | static void | ||
426 | isac_cisq_irq(struct isac_hw *isac) { | ||
427 | u8 val; | ||
428 | |||
429 | val = ReadISAC(isac, ISAC_CIR0); | ||
430 | pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val); | ||
431 | if (val & 2) { | ||
432 | pr_debug("%s: ph_state change %x->%x\n", isac->name, | ||
433 | isac->state, (val >> 2) & 0xf); | ||
434 | isac->state = (val >> 2) & 0xf; | ||
435 | isac_ph_state_change(isac); | ||
436 | } | ||
437 | if (val & 1) { | ||
438 | val = ReadISAC(isac, ISAC_CIR1); | ||
439 | pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | static void | ||
444 | isacsx_cic_irq(struct isac_hw *isac) | ||
445 | { | ||
446 | u8 val; | ||
447 | |||
448 | val = ReadISAC(isac, ISACX_CIR0); | ||
449 | pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); | ||
450 | if (val & ISACX_CIR0_CIC0) { | ||
451 | pr_debug("%s: ph_state change %x->%x\n", isac->name, | ||
452 | isac->state, val >> 4); | ||
453 | isac->state = val >> 4; | ||
454 | isac_ph_state_change(isac); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | static void | ||
459 | isacsx_rme_irq(struct isac_hw *isac) | ||
460 | { | ||
461 | int count; | ||
462 | u8 val; | ||
463 | |||
464 | val = ReadISAC(isac, ISACX_RSTAD); | ||
465 | if ((val & (ISACX_RSTAD_VFR | | ||
466 | ISACX_RSTAD_RDO | | ||
467 | ISACX_RSTAD_CRC | | ||
468 | ISACX_RSTAD_RAB)) | ||
469 | != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) { | ||
470 | pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val); | ||
471 | #ifdef ERROR_STATISTIC | ||
472 | if (val & ISACX_RSTAD_CRC) | ||
473 | isac->dch.err_rx++; | ||
474 | else | ||
475 | isac->dch.err_crc++; | ||
476 | #endif | ||
477 | WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); | ||
478 | if (isac->dch.rx_skb) | ||
479 | dev_kfree_skb(isac->dch.rx_skb); | ||
480 | isac->dch.rx_skb = NULL; | ||
481 | } else { | ||
482 | count = ReadISAC(isac, ISACX_RBCLD) & 0x1f; | ||
483 | if (count == 0) | ||
484 | count = 32; | ||
485 | isac_empty_fifo(isac, count); | ||
486 | if (isac->dch.rx_skb) { | ||
487 | skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1); | ||
488 | pr_debug("%s: dchannel received %d\n", isac->name, | ||
489 | isac->dch.rx_skb->len); | ||
490 | recv_Dchannel(&isac->dch); | ||
491 | } | ||
492 | } | ||
493 | } | ||
494 | |||
495 | irqreturn_t | ||
496 | mISDNisac_irq(struct isac_hw *isac, u8 val) | ||
497 | { | ||
498 | if (unlikely(!val)) | ||
499 | return IRQ_NONE; | ||
500 | pr_debug("%s: ISAC interrupt %02x\n", isac->name, val); | ||
501 | if (isac->type & IPAC_TYPE_ISACX) { | ||
502 | if (val & ISACX__CIC) | ||
503 | isacsx_cic_irq(isac); | ||
504 | if (val & ISACX__ICD) { | ||
505 | val = ReadISAC(isac, ISACX_ISTAD); | ||
506 | pr_debug("%s: ISTAD %02x\n", isac->name, val); | ||
507 | if (val & ISACX_D_XDU) { | ||
508 | pr_debug("%s: ISAC XDU\n", isac->name); | ||
509 | #ifdef ERROR_STATISTIC | ||
510 | isac->dch.err_tx++; | ||
511 | #endif | ||
512 | isac_retransmit(isac); | ||
513 | } | ||
514 | if (val & ISACX_D_XMR) { | ||
515 | pr_debug("%s: ISAC XMR\n", isac->name); | ||
516 | #ifdef ERROR_STATISTIC | ||
517 | isac->dch.err_tx++; | ||
518 | #endif | ||
519 | isac_retransmit(isac); | ||
520 | } | ||
521 | if (val & ISACX_D_XPR) | ||
522 | isac_xpr_irq(isac); | ||
523 | if (val & ISACX_D_RFO) { | ||
524 | pr_debug("%s: ISAC RFO\n", isac->name); | ||
525 | WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); | ||
526 | } | ||
527 | if (val & ISACX_D_RME) | ||
528 | isacsx_rme_irq(isac); | ||
529 | if (val & ISACX_D_RPF) | ||
530 | isac_empty_fifo(isac, 0x20); | ||
531 | } | ||
532 | } else { | ||
533 | if (val & 0x80) /* RME */ | ||
534 | isac_rme_irq(isac); | ||
535 | if (val & 0x40) /* RPF */ | ||
536 | isac_empty_fifo(isac, 32); | ||
537 | if (val & 0x10) /* XPR */ | ||
538 | isac_xpr_irq(isac); | ||
539 | if (val & 0x04) /* CISQ */ | ||
540 | isac_cisq_irq(isac); | ||
541 | if (val & 0x20) /* RSC - never */ | ||
542 | pr_debug("%s: ISAC RSC interrupt\n", isac->name); | ||
543 | if (val & 0x02) /* SIN - never */ | ||
544 | pr_debug("%s: ISAC SIN interrupt\n", isac->name); | ||
545 | if (val & 0x01) { /* EXI */ | ||
546 | val = ReadISAC(isac, ISAC_EXIR); | ||
547 | pr_debug("%s: ISAC EXIR %02x\n", isac->name, val); | ||
548 | if (val & 0x80) /* XMR */ | ||
549 | pr_debug("%s: ISAC XMR\n", isac->name); | ||
550 | if (val & 0x40) { /* XDU */ | ||
551 | pr_debug("%s: ISAC XDU\n", isac->name); | ||
552 | #ifdef ERROR_STATISTIC | ||
553 | isac->dch.err_tx++; | ||
554 | #endif | ||
555 | isac_retransmit(isac); | ||
556 | } | ||
557 | if (val & 0x04) /* MOS */ | ||
558 | isac_mos_irq(isac); | ||
559 | } | ||
560 | } | ||
561 | return IRQ_HANDLED; | ||
562 | } | ||
563 | EXPORT_SYMBOL(mISDNisac_irq); | ||
564 | |||
565 | static int | ||
566 | isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb) | ||
567 | { | ||
568 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
569 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
570 | struct isac_hw *isac = container_of(dch, struct isac_hw, dch); | ||
571 | int ret = -EINVAL; | ||
572 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
573 | u32 id; | ||
574 | u_long flags; | ||
575 | |||
576 | switch (hh->prim) { | ||
577 | case PH_DATA_REQ: | ||
578 | spin_lock_irqsave(isac->hwlock, flags); | ||
579 | ret = dchannel_senddata(dch, skb); | ||
580 | if (ret > 0) { /* direct TX */ | ||
581 | id = hh->id; /* skb can be freed */ | ||
582 | isac_fill_fifo(isac); | ||
583 | ret = 0; | ||
584 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
585 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
586 | } else | ||
587 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
588 | return ret; | ||
589 | case PH_ACTIVATE_REQ: | ||
590 | ret = l1_event(dch->l1, hh->prim); | ||
591 | break; | ||
592 | case PH_DEACTIVATE_REQ: | ||
593 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
594 | ret = l1_event(dch->l1, hh->prim); | ||
595 | break; | ||
596 | } | ||
597 | |||
598 | if (!ret) | ||
599 | dev_kfree_skb(skb); | ||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | static int | ||
604 | isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para) | ||
605 | { | ||
606 | u8 tl = 0; | ||
607 | u_long flags; | ||
608 | |||
609 | switch (cmd) { | ||
610 | case HW_TESTLOOP: | ||
611 | spin_lock_irqsave(isac->hwlock, flags); | ||
612 | if (!(isac->type & IPAC_TYPE_ISACX)) { | ||
613 | /* TODO: implement for IPAC_TYPE_ISACX */ | ||
614 | if (para & 1) /* B1 */ | ||
615 | tl |= 0x0c; | ||
616 | else if (para & 2) /* B2 */ | ||
617 | tl |= 0x3; | ||
618 | /* we only support IOM2 mode */ | ||
619 | WriteISAC(isac, ISAC_SPCR, tl); | ||
620 | if (tl) | ||
621 | WriteISAC(isac, ISAC_ADF1, 0x8); | ||
622 | else | ||
623 | WriteISAC(isac, ISAC_ADF1, 0x0); | ||
624 | } | ||
625 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
626 | break; | ||
627 | default: | ||
628 | pr_debug("%s: %s unknown command %x %lx\n", isac->name, | ||
629 | __func__, cmd, para); | ||
630 | return -1; | ||
631 | } | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static int | ||
636 | isac_l1cmd(struct dchannel *dch, u32 cmd) | ||
637 | { | ||
638 | struct isac_hw *isac = container_of(dch, struct isac_hw, dch); | ||
639 | u_long flags; | ||
640 | |||
641 | pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state); | ||
642 | switch (cmd) { | ||
643 | case INFO3_P8: | ||
644 | spin_lock_irqsave(isac->hwlock, flags); | ||
645 | ph_command(isac, ISAC_CMD_AR8); | ||
646 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
647 | break; | ||
648 | case INFO3_P10: | ||
649 | spin_lock_irqsave(isac->hwlock, flags); | ||
650 | ph_command(isac, ISAC_CMD_AR10); | ||
651 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
652 | break; | ||
653 | case HW_RESET_REQ: | ||
654 | spin_lock_irqsave(isac->hwlock, flags); | ||
655 | if ((isac->state == ISAC_IND_EI) || | ||
656 | (isac->state == ISAC_IND_DR) || | ||
657 | (isac->state == ISAC_IND_RS)) | ||
658 | ph_command(isac, ISAC_CMD_TIM); | ||
659 | else | ||
660 | ph_command(isac, ISAC_CMD_RS); | ||
661 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
662 | break; | ||
663 | case HW_DEACT_REQ: | ||
664 | skb_queue_purge(&dch->squeue); | ||
665 | if (dch->tx_skb) { | ||
666 | dev_kfree_skb(dch->tx_skb); | ||
667 | dch->tx_skb = NULL; | ||
668 | } | ||
669 | dch->tx_idx = 0; | ||
670 | if (dch->rx_skb) { | ||
671 | dev_kfree_skb(dch->rx_skb); | ||
672 | dch->rx_skb = NULL; | ||
673 | } | ||
674 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
675 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
676 | del_timer(&dch->timer); | ||
677 | break; | ||
678 | case HW_POWERUP_REQ: | ||
679 | spin_lock_irqsave(isac->hwlock, flags); | ||
680 | ph_command(isac, ISAC_CMD_TIM); | ||
681 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
682 | break; | ||
683 | case PH_ACTIVATE_IND: | ||
684 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
685 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
686 | GFP_ATOMIC); | ||
687 | break; | ||
688 | case PH_DEACTIVATE_IND: | ||
689 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
690 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
691 | GFP_ATOMIC); | ||
692 | break; | ||
693 | default: | ||
694 | pr_debug("%s: %s unknown command %x\n", isac->name, | ||
695 | __func__, cmd); | ||
696 | return -1; | ||
697 | } | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static void | ||
702 | isac_release(struct isac_hw *isac) | ||
703 | { | ||
704 | if (isac->type & IPAC_TYPE_ISACX) | ||
705 | WriteISAC(isac, ISACX_MASK, 0xff); | ||
706 | else | ||
707 | WriteISAC(isac, ISAC_MASK, 0xff); | ||
708 | if (isac->dch.timer.function != NULL) { | ||
709 | del_timer(&isac->dch.timer); | ||
710 | isac->dch.timer.function = NULL; | ||
711 | } | ||
712 | kfree(isac->mon_rx); | ||
713 | isac->mon_rx = NULL; | ||
714 | kfree(isac->mon_tx); | ||
715 | isac->mon_tx = NULL; | ||
716 | if (isac->dch.l1) | ||
717 | l1_event(isac->dch.l1, CLOSE_CHANNEL); | ||
718 | mISDN_freedchannel(&isac->dch); | ||
719 | } | ||
720 | |||
721 | static void | ||
722 | dbusy_timer_handler(struct isac_hw *isac) | ||
723 | { | ||
724 | int rbch, star; | ||
725 | u_long flags; | ||
726 | |||
727 | if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { | ||
728 | spin_lock_irqsave(isac->hwlock, flags); | ||
729 | rbch = ReadISAC(isac, ISAC_RBCH); | ||
730 | star = ReadISAC(isac, ISAC_STAR); | ||
731 | pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", | ||
732 | isac->name, rbch, star); | ||
733 | if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */ | ||
734 | test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags); | ||
735 | else { | ||
736 | /* discard frame; reset transceiver */ | ||
737 | test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags); | ||
738 | if (isac->dch.tx_idx) | ||
739 | isac->dch.tx_idx = 0; | ||
740 | else | ||
741 | pr_info("%s: ISAC D-Channel Busy no tx_idx\n", | ||
742 | isac->name); | ||
743 | /* Transmitter reset */ | ||
744 | WriteISAC(isac, ISAC_CMDR, 0x01); | ||
745 | } | ||
746 | spin_unlock_irqrestore(isac->hwlock, flags); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | static int | ||
751 | open_dchannel(struct isac_hw *isac, struct channel_req *rq) | ||
752 | { | ||
753 | pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__, | ||
754 | isac->dch.dev.id, __builtin_return_address(1)); | ||
755 | if (rq->protocol != ISDN_P_TE_S0) | ||
756 | return -EINVAL; | ||
757 | if (rq->adr.channel == 1) | ||
758 | /* E-Channel not supported */ | ||
759 | return -EINVAL; | ||
760 | rq->ch = &isac->dch.dev.D; | ||
761 | rq->ch->protocol = rq->protocol; | ||
762 | if (isac->dch.state == 7) | ||
763 | _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
764 | 0, NULL, GFP_KERNEL); | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static const char *ISACVer[] = | ||
769 | {"2086/2186 V1.1", "2085 B1", "2085 B2", | ||
770 | "2085 V2.3"}; | ||
771 | |||
772 | static int | ||
773 | isac_init(struct isac_hw *isac) | ||
774 | { | ||
775 | u8 val; | ||
776 | int err = 0; | ||
777 | |||
778 | if (!isac->dch.l1) { | ||
779 | err = create_l1(&isac->dch, isac_l1cmd); | ||
780 | if (err) | ||
781 | return err; | ||
782 | } | ||
783 | isac->mon_tx = NULL; | ||
784 | isac->mon_rx = NULL; | ||
785 | isac->dch.timer.function = (void *) dbusy_timer_handler; | ||
786 | isac->dch.timer.data = (long)isac; | ||
787 | init_timer(&isac->dch.timer); | ||
788 | isac->mocr = 0xaa; | ||
789 | if (isac->type & IPAC_TYPE_ISACX) { | ||
790 | /* Disable all IRQ */ | ||
791 | WriteISAC(isac, ISACX_MASK, 0xff); | ||
792 | val = ReadISAC(isac, ISACX_STARD); | ||
793 | pr_debug("%s: ISACX STARD %x\n", isac->name, val); | ||
794 | val = ReadISAC(isac, ISACX_ISTAD); | ||
795 | pr_debug("%s: ISACX ISTAD %x\n", isac->name, val); | ||
796 | val = ReadISAC(isac, ISACX_ISTA); | ||
797 | pr_debug("%s: ISACX ISTA %x\n", isac->name, val); | ||
798 | /* clear LDD */ | ||
799 | WriteISAC(isac, ISACX_TR_CONF0, 0x00); | ||
800 | /* enable transmitter */ | ||
801 | WriteISAC(isac, ISACX_TR_CONF2, 0x00); | ||
802 | /* transparent mode 0, RAC, stop/go */ | ||
803 | WriteISAC(isac, ISACX_MODED, 0xc9); | ||
804 | /* all HDLC IRQ unmasked */ | ||
805 | val = ReadISAC(isac, ISACX_ID); | ||
806 | if (isac->dch.debug & DEBUG_HW) | ||
807 | pr_notice("%s: ISACX Design ID %x\n", | ||
808 | isac->name, val & 0x3f); | ||
809 | val = ReadISAC(isac, ISACX_CIR0); | ||
810 | pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); | ||
811 | isac->state = val >> 4; | ||
812 | isac_ph_state_change(isac); | ||
813 | ph_command(isac, ISAC_CMD_RS); | ||
814 | WriteISAC(isac, ISACX_MASK, IPACX__ON); | ||
815 | WriteISAC(isac, ISACX_MASKD, 0x00); | ||
816 | } else { /* old isac */ | ||
817 | WriteISAC(isac, ISAC_MASK, 0xff); | ||
818 | val = ReadISAC(isac, ISAC_STAR); | ||
819 | pr_debug("%s: ISAC STAR %x\n", isac->name, val); | ||
820 | val = ReadISAC(isac, ISAC_MODE); | ||
821 | pr_debug("%s: ISAC MODE %x\n", isac->name, val); | ||
822 | val = ReadISAC(isac, ISAC_ADF2); | ||
823 | pr_debug("%s: ISAC ADF2 %x\n", isac->name, val); | ||
824 | val = ReadISAC(isac, ISAC_ISTA); | ||
825 | pr_debug("%s: ISAC ISTA %x\n", isac->name, val); | ||
826 | if (val & 0x01) { | ||
827 | val = ReadISAC(isac, ISAC_EXIR); | ||
828 | pr_debug("%s: ISAC EXIR %x\n", isac->name, val); | ||
829 | } | ||
830 | val = ReadISAC(isac, ISAC_RBCH); | ||
831 | if (isac->dch.debug & DEBUG_HW) | ||
832 | pr_notice("%s: ISAC version (%x): %s\n", isac->name, | ||
833 | val, ISACVer[(val >> 5) & 3]); | ||
834 | isac->type |= ((val >> 5) & 3); | ||
835 | if (!isac->adf2) | ||
836 | isac->adf2 = 0x80; | ||
837 | if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */ | ||
838 | pr_info("%s: only support IOM2 mode but adf2=%02x\n", | ||
839 | isac->name, isac->adf2); | ||
840 | isac_release(isac); | ||
841 | return -EINVAL; | ||
842 | } | ||
843 | WriteISAC(isac, ISAC_ADF2, isac->adf2); | ||
844 | WriteISAC(isac, ISAC_SQXR, 0x2f); | ||
845 | WriteISAC(isac, ISAC_SPCR, 0x00); | ||
846 | WriteISAC(isac, ISAC_STCR, 0x70); | ||
847 | WriteISAC(isac, ISAC_MODE, 0xc9); | ||
848 | WriteISAC(isac, ISAC_TIMR, 0x00); | ||
849 | WriteISAC(isac, ISAC_ADF1, 0x00); | ||
850 | val = ReadISAC(isac, ISAC_CIR0); | ||
851 | pr_debug("%s: ISAC CIR0 %x\n", isac->name, val); | ||
852 | isac->state = (val >> 2) & 0xf; | ||
853 | isac_ph_state_change(isac); | ||
854 | ph_command(isac, ISAC_CMD_RS); | ||
855 | WriteISAC(isac, ISAC_MASK, 0); | ||
856 | } | ||
857 | return err; | ||
858 | } | ||
859 | |||
860 | int | ||
861 | mISDNisac_init(struct isac_hw *isac, void *hw) | ||
862 | { | ||
863 | mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh); | ||
864 | isac->dch.hw = hw; | ||
865 | isac->dch.dev.D.send = isac_l1hw; | ||
866 | isac->init = isac_init; | ||
867 | isac->release = isac_release; | ||
868 | isac->ctrl = isac_ctrl; | ||
869 | isac->open = open_dchannel; | ||
870 | isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); | ||
871 | isac->dch.dev.nrbchan = 2; | ||
872 | return 0; | ||
873 | } | ||
874 | EXPORT_SYMBOL(mISDNisac_init); | ||
875 | |||
876 | static void | ||
877 | waitforCEC(struct hscx_hw *hx) | ||
878 | { | ||
879 | u8 starb, to = 50; | ||
880 | |||
881 | while (to) { | ||
882 | starb = ReadHSCX(hx, IPAC_STARB); | ||
883 | if (!(starb & 0x04)) | ||
884 | break; | ||
885 | udelay(1); | ||
886 | to--; | ||
887 | } | ||
888 | if (to < 50) | ||
889 | pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr, | ||
890 | 50 - to); | ||
891 | if (!to) | ||
892 | pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr); | ||
893 | } | ||
894 | |||
895 | |||
896 | static void | ||
897 | waitforXFW(struct hscx_hw *hx) | ||
898 | { | ||
899 | u8 starb, to = 50; | ||
900 | |||
901 | while (to) { | ||
902 | starb = ReadHSCX(hx, IPAC_STARB); | ||
903 | if ((starb & 0x44) == 0x40) | ||
904 | break; | ||
905 | udelay(1); | ||
906 | to--; | ||
907 | } | ||
908 | if (to < 50) | ||
909 | pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr, | ||
910 | 50 - to); | ||
911 | if (!to) | ||
912 | pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr); | ||
913 | } | ||
914 | |||
915 | static void | ||
916 | hscx_cmdr(struct hscx_hw *hx, u8 cmd) | ||
917 | { | ||
918 | if (hx->ip->type & IPAC_TYPE_IPACX) | ||
919 | WriteHSCX(hx, IPACX_CMDRB, cmd); | ||
920 | else { | ||
921 | waitforCEC(hx); | ||
922 | WriteHSCX(hx, IPAC_CMDRB, cmd); | ||
923 | } | ||
924 | } | ||
925 | |||
926 | static void | ||
927 | hscx_empty_fifo(struct hscx_hw *hscx, u8 count) | ||
928 | { | ||
929 | u8 *p; | ||
930 | |||
931 | pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); | ||
932 | if (!hscx->bch.rx_skb) { | ||
933 | hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC); | ||
934 | if (!hscx->bch.rx_skb) { | ||
935 | pr_info("%s: B receive out of memory\n", | ||
936 | hscx->ip->name); | ||
937 | hscx_cmdr(hscx, 0x80); /* RMC */ | ||
938 | return; | ||
939 | } | ||
940 | } | ||
941 | if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) { | ||
942 | pr_debug("%s: overrun %d\n", hscx->ip->name, | ||
943 | hscx->bch.rx_skb->len + count); | ||
944 | skb_trim(hscx->bch.rx_skb, 0); | ||
945 | hscx_cmdr(hscx, 0x80); /* RMC */ | ||
946 | return; | ||
947 | } | ||
948 | p = skb_put(hscx->bch.rx_skb, count); | ||
949 | |||
950 | if (hscx->ip->type & IPAC_TYPE_IPACX) | ||
951 | hscx->ip->read_fifo(hscx->ip->hw, | ||
952 | hscx->off + IPACX_RFIFOB, p, count); | ||
953 | else | ||
954 | hscx->ip->read_fifo(hscx->ip->hw, | ||
955 | hscx->off, p, count); | ||
956 | |||
957 | hscx_cmdr(hscx, 0x80); /* RMC */ | ||
958 | |||
959 | if (hscx->bch.debug & DEBUG_HW_BFIFO) { | ||
960 | snprintf(hscx->log, 64, "B%1d-recv %s %d ", | ||
961 | hscx->bch.nr, hscx->ip->name, count); | ||
962 | print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); | ||
963 | } | ||
964 | } | ||
965 | |||
966 | static void | ||
967 | hscx_fill_fifo(struct hscx_hw *hscx) | ||
968 | { | ||
969 | int count, more; | ||
970 | u8 *p; | ||
971 | |||
972 | if (!hscx->bch.tx_skb) | ||
973 | return; | ||
974 | count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; | ||
975 | if (count <= 0) | ||
976 | return; | ||
977 | p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; | ||
978 | |||
979 | more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; | ||
980 | if (count > hscx->fifo_size) { | ||
981 | count = hscx->fifo_size; | ||
982 | more = 1; | ||
983 | } | ||
984 | pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count, | ||
985 | hscx->bch.tx_idx, hscx->bch.tx_skb->len); | ||
986 | hscx->bch.tx_idx += count; | ||
987 | |||
988 | if (hscx->ip->type & IPAC_TYPE_IPACX) | ||
989 | hscx->ip->write_fifo(hscx->ip->hw, | ||
990 | hscx->off + IPACX_XFIFOB, p, count); | ||
991 | else { | ||
992 | waitforXFW(hscx); | ||
993 | hscx->ip->write_fifo(hscx->ip->hw, | ||
994 | hscx->off, p, count); | ||
995 | } | ||
996 | hscx_cmdr(hscx, more ? 0x08 : 0x0a); | ||
997 | |||
998 | if (hscx->bch.debug & DEBUG_HW_BFIFO) { | ||
999 | snprintf(hscx->log, 64, "B%1d-send %s %d ", | ||
1000 | hscx->bch.nr, hscx->ip->name, count); | ||
1001 | print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | static void | ||
1006 | hscx_xpr(struct hscx_hw *hx) | ||
1007 | { | ||
1008 | if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) | ||
1009 | hscx_fill_fifo(hx); | ||
1010 | else { | ||
1011 | if (hx->bch.tx_skb) { | ||
1012 | /* send confirm, on trans, free on hdlc. */ | ||
1013 | if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) | ||
1014 | confirm_Bsend(&hx->bch); | ||
1015 | dev_kfree_skb(hx->bch.tx_skb); | ||
1016 | } | ||
1017 | if (get_next_bframe(&hx->bch)) | ||
1018 | hscx_fill_fifo(hx); | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | static void | ||
1023 | ipac_rme(struct hscx_hw *hx) | ||
1024 | { | ||
1025 | int count; | ||
1026 | u8 rstab; | ||
1027 | |||
1028 | if (hx->ip->type & IPAC_TYPE_IPACX) | ||
1029 | rstab = ReadHSCX(hx, IPACX_RSTAB); | ||
1030 | else | ||
1031 | rstab = ReadHSCX(hx, IPAC_RSTAB); | ||
1032 | pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab); | ||
1033 | if ((rstab & 0xf0) != 0xa0) { | ||
1034 | /* !(VFR && !RDO && CRC && !RAB) */ | ||
1035 | if (!(rstab & 0x80)) { | ||
1036 | if (hx->bch.debug & DEBUG_HW_BCHANNEL) | ||
1037 | pr_notice("%s: B%1d invalid frame\n", | ||
1038 | hx->ip->name, hx->bch.nr); | ||
1039 | } | ||
1040 | if (rstab & 0x40) { | ||
1041 | if (hx->bch.debug & DEBUG_HW_BCHANNEL) | ||
1042 | pr_notice("%s: B%1d RDO proto=%x\n", | ||
1043 | hx->ip->name, hx->bch.nr, | ||
1044 | hx->bch.state); | ||
1045 | } | ||
1046 | if (!(rstab & 0x20)) { | ||
1047 | if (hx->bch.debug & DEBUG_HW_BCHANNEL) | ||
1048 | pr_notice("%s: B%1d CRC error\n", | ||
1049 | hx->ip->name, hx->bch.nr); | ||
1050 | } | ||
1051 | hscx_cmdr(hx, 0x80); /* Do RMC */ | ||
1052 | return; | ||
1053 | } | ||
1054 | if (hx->ip->type & IPAC_TYPE_IPACX) | ||
1055 | count = ReadHSCX(hx, IPACX_RBCLB); | ||
1056 | else | ||
1057 | count = ReadHSCX(hx, IPAC_RBCLB); | ||
1058 | count &= (hx->fifo_size - 1); | ||
1059 | if (count == 0) | ||
1060 | count = hx->fifo_size; | ||
1061 | hscx_empty_fifo(hx, count); | ||
1062 | if (!hx->bch.rx_skb) | ||
1063 | return; | ||
1064 | if (hx->bch.rx_skb->len < 2) { | ||
1065 | pr_debug("%s: B%1d frame to short %d\n", | ||
1066 | hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len); | ||
1067 | skb_trim(hx->bch.rx_skb, 0); | ||
1068 | } else { | ||
1069 | skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); | ||
1070 | recv_Bchannel(&hx->bch, 0); | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | static void | ||
1075 | ipac_irq(struct hscx_hw *hx, u8 ista) | ||
1076 | { | ||
1077 | u8 istab, m, exirb = 0; | ||
1078 | |||
1079 | if (hx->ip->type & IPAC_TYPE_IPACX) | ||
1080 | istab = ReadHSCX(hx, IPACX_ISTAB); | ||
1081 | else if (hx->ip->type & IPAC_TYPE_IPAC) { | ||
1082 | istab = ReadHSCX(hx, IPAC_ISTAB); | ||
1083 | m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB; | ||
1084 | if (m & ista) { | ||
1085 | exirb = ReadHSCX(hx, IPAC_EXIRB); | ||
1086 | pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, | ||
1087 | hx->bch.nr, exirb); | ||
1088 | } | ||
1089 | } else if (hx->bch.nr & 2) { /* HSCX B */ | ||
1090 | if (ista & (HSCX__EXA | HSCX__ICA)) | ||
1091 | ipac_irq(&hx->ip->hscx[0], ista); | ||
1092 | if (ista & HSCX__EXB) { | ||
1093 | exirb = ReadHSCX(hx, IPAC_EXIRB); | ||
1094 | pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, | ||
1095 | hx->bch.nr, exirb); | ||
1096 | } | ||
1097 | istab = ista & 0xF8; | ||
1098 | } else { /* HSCX A */ | ||
1099 | istab = ReadHSCX(hx, IPAC_ISTAB); | ||
1100 | if (ista & HSCX__EXA) { | ||
1101 | exirb = ReadHSCX(hx, IPAC_EXIRB); | ||
1102 | pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, | ||
1103 | hx->bch.nr, exirb); | ||
1104 | } | ||
1105 | istab = istab & 0xF8; | ||
1106 | } | ||
1107 | if (exirb & IPAC_B_XDU) | ||
1108 | istab |= IPACX_B_XDU; | ||
1109 | if (exirb & IPAC_B_RFO) | ||
1110 | istab |= IPACX_B_RFO; | ||
1111 | pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab); | ||
1112 | |||
1113 | if (!test_bit(FLG_ACTIVE, &hx->bch.Flags)) | ||
1114 | return; | ||
1115 | |||
1116 | if (istab & IPACX_B_RME) | ||
1117 | ipac_rme(hx); | ||
1118 | |||
1119 | if (istab & IPACX_B_RPF) { | ||
1120 | hscx_empty_fifo(hx, hx->fifo_size); | ||
1121 | if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { | ||
1122 | /* receive transparent audio data */ | ||
1123 | if (hx->bch.rx_skb) | ||
1124 | recv_Bchannel(&hx->bch, 0); | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | if (istab & IPACX_B_RFO) { | ||
1129 | pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr); | ||
1130 | hscx_cmdr(hx, 0x40); /* RRES */ | ||
1131 | } | ||
1132 | |||
1133 | if (istab & IPACX_B_XPR) | ||
1134 | hscx_xpr(hx); | ||
1135 | |||
1136 | if (istab & IPACX_B_XDU) { | ||
1137 | if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { | ||
1138 | hscx_fill_fifo(hx); | ||
1139 | return; | ||
1140 | } | ||
1141 | pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, | ||
1142 | hx->bch.nr, hx->bch.tx_idx); | ||
1143 | hx->bch.tx_idx = 0; | ||
1144 | hscx_cmdr(hx, 0x01); /* XRES */ | ||
1145 | } | ||
1146 | } | ||
1147 | |||
1148 | irqreturn_t | ||
1149 | mISDNipac_irq(struct ipac_hw *ipac, int maxloop) | ||
1150 | { | ||
1151 | int cnt = maxloop + 1; | ||
1152 | u8 ista, istad; | ||
1153 | struct isac_hw *isac = &ipac->isac; | ||
1154 | |||
1155 | if (ipac->type & IPAC_TYPE_IPACX) { | ||
1156 | ista = ReadIPAC(ipac, ISACX_ISTA); | ||
1157 | while (ista && cnt--) { | ||
1158 | pr_debug("%s: ISTA %02x\n", ipac->name, ista); | ||
1159 | if (ista & IPACX__ICA) | ||
1160 | ipac_irq(&ipac->hscx[0], ista); | ||
1161 | if (ista & IPACX__ICB) | ||
1162 | ipac_irq(&ipac->hscx[1], ista); | ||
1163 | if (ista & (ISACX__ICD | ISACX__CIC)) | ||
1164 | mISDNisac_irq(&ipac->isac, ista); | ||
1165 | ista = ReadIPAC(ipac, ISACX_ISTA); | ||
1166 | } | ||
1167 | } else if (ipac->type & IPAC_TYPE_IPAC) { | ||
1168 | ista = ReadIPAC(ipac, IPAC_ISTA); | ||
1169 | while (ista && cnt--) { | ||
1170 | pr_debug("%s: ISTA %02x\n", ipac->name, ista); | ||
1171 | if (ista & (IPAC__ICD | IPAC__EXD)) { | ||
1172 | istad = ReadISAC(isac, ISAC_ISTA); | ||
1173 | pr_debug("%s: ISTAD %02x\n", ipac->name, istad); | ||
1174 | if (istad & IPAC_D_TIN2) | ||
1175 | pr_debug("%s TIN2 irq\n", ipac->name); | ||
1176 | if (ista & IPAC__EXD) | ||
1177 | istad |= 1; /* ISAC EXI */ | ||
1178 | mISDNisac_irq(isac, istad); | ||
1179 | } | ||
1180 | if (ista & (IPAC__ICA | IPAC__EXA)) | ||
1181 | ipac_irq(&ipac->hscx[0], ista); | ||
1182 | if (ista & (IPAC__ICB | IPAC__EXB)) | ||
1183 | ipac_irq(&ipac->hscx[1], ista); | ||
1184 | ista = ReadIPAC(ipac, IPAC_ISTA); | ||
1185 | } | ||
1186 | } else if (ipac->type & IPAC_TYPE_HSCX) { | ||
1187 | while (cnt) { | ||
1188 | ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off); | ||
1189 | pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista); | ||
1190 | if (ista) | ||
1191 | ipac_irq(&ipac->hscx[1], ista); | ||
1192 | istad = ReadISAC(isac, ISAC_ISTA); | ||
1193 | pr_debug("%s: ISTAD %02x\n", ipac->name, istad); | ||
1194 | if (istad) | ||
1195 | mISDNisac_irq(isac, istad); | ||
1196 | if (0 == (ista | istad)) | ||
1197 | break; | ||
1198 | cnt--; | ||
1199 | } | ||
1200 | } | ||
1201 | if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */ | ||
1202 | return IRQ_NONE; | ||
1203 | if (cnt < maxloop) | ||
1204 | pr_debug("%s: %d irqloops cpu%d\n", ipac->name, | ||
1205 | maxloop - cnt, smp_processor_id()); | ||
1206 | if (maxloop && !cnt) | ||
1207 | pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name, | ||
1208 | maxloop, smp_processor_id()); | ||
1209 | return IRQ_HANDLED; | ||
1210 | } | ||
1211 | EXPORT_SYMBOL(mISDNipac_irq); | ||
1212 | |||
1213 | static int | ||
1214 | hscx_mode(struct hscx_hw *hscx, u32 bprotocol) | ||
1215 | { | ||
1216 | pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name, | ||
1217 | '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr); | ||
1218 | if (hscx->ip->type & IPAC_TYPE_IPACX) { | ||
1219 | if (hscx->bch.nr & 1) { /* B1 and ICA */ | ||
1220 | WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80); | ||
1221 | WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88); | ||
1222 | } else { /* B2 and ICB */ | ||
1223 | WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81); | ||
1224 | WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88); | ||
1225 | } | ||
1226 | switch (bprotocol) { | ||
1227 | case ISDN_P_NONE: /* init */ | ||
1228 | WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */ | ||
1229 | WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */ | ||
1230 | WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */ | ||
1231 | hscx_cmdr(hscx, 0x41); | ||
1232 | test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); | ||
1233 | test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); | ||
1234 | break; | ||
1235 | case ISDN_P_B_RAW: | ||
1236 | WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */ | ||
1237 | WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */ | ||
1238 | hscx_cmdr(hscx, 0x41); | ||
1239 | WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); | ||
1240 | test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); | ||
1241 | break; | ||
1242 | case ISDN_P_B_HDLC: | ||
1243 | WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */ | ||
1244 | WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */ | ||
1245 | hscx_cmdr(hscx, 0x41); | ||
1246 | WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); | ||
1247 | test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); | ||
1248 | break; | ||
1249 | default: | ||
1250 | pr_info("%s: protocol not known %x\n", hscx->ip->name, | ||
1251 | bprotocol); | ||
1252 | return -ENOPROTOOPT; | ||
1253 | } | ||
1254 | } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */ | ||
1255 | WriteHSCX(hscx, IPAC_CCR1, 0x82); | ||
1256 | WriteHSCX(hscx, IPAC_CCR2, 0x30); | ||
1257 | WriteHSCX(hscx, IPAC_XCCR, 0x07); | ||
1258 | WriteHSCX(hscx, IPAC_RCCR, 0x07); | ||
1259 | WriteHSCX(hscx, IPAC_TSAX, hscx->slot); | ||
1260 | WriteHSCX(hscx, IPAC_TSAR, hscx->slot); | ||
1261 | switch (bprotocol) { | ||
1262 | case ISDN_P_NONE: | ||
1263 | WriteHSCX(hscx, IPAC_TSAX, 0x1F); | ||
1264 | WriteHSCX(hscx, IPAC_TSAR, 0x1F); | ||
1265 | WriteHSCX(hscx, IPAC_MODEB, 0x84); | ||
1266 | WriteHSCX(hscx, IPAC_CCR1, 0x82); | ||
1267 | WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ | ||
1268 | test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); | ||
1269 | test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); | ||
1270 | break; | ||
1271 | case ISDN_P_B_RAW: | ||
1272 | WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ | ||
1273 | WriteHSCX(hscx, IPAC_CCR1, 0x82); | ||
1274 | hscx_cmdr(hscx, 0x41); | ||
1275 | WriteHSCX(hscx, IPAC_MASKB, 0); | ||
1276 | test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); | ||
1277 | break; | ||
1278 | case ISDN_P_B_HDLC: | ||
1279 | WriteHSCX(hscx, IPAC_MODEB, 0x8c); | ||
1280 | WriteHSCX(hscx, IPAC_CCR1, 0x8a); | ||
1281 | hscx_cmdr(hscx, 0x41); | ||
1282 | WriteHSCX(hscx, IPAC_MASKB, 0); | ||
1283 | test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); | ||
1284 | break; | ||
1285 | default: | ||
1286 | pr_info("%s: protocol not known %x\n", hscx->ip->name, | ||
1287 | bprotocol); | ||
1288 | return -ENOPROTOOPT; | ||
1289 | } | ||
1290 | } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */ | ||
1291 | WriteHSCX(hscx, IPAC_CCR1, 0x85); | ||
1292 | WriteHSCX(hscx, IPAC_CCR2, 0x30); | ||
1293 | WriteHSCX(hscx, IPAC_XCCR, 0x07); | ||
1294 | WriteHSCX(hscx, IPAC_RCCR, 0x07); | ||
1295 | WriteHSCX(hscx, IPAC_TSAX, hscx->slot); | ||
1296 | WriteHSCX(hscx, IPAC_TSAR, hscx->slot); | ||
1297 | switch (bprotocol) { | ||
1298 | case ISDN_P_NONE: | ||
1299 | WriteHSCX(hscx, IPAC_TSAX, 0x1F); | ||
1300 | WriteHSCX(hscx, IPAC_TSAR, 0x1F); | ||
1301 | WriteHSCX(hscx, IPAC_MODEB, 0x84); | ||
1302 | WriteHSCX(hscx, IPAC_CCR1, 0x85); | ||
1303 | WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ | ||
1304 | test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); | ||
1305 | test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); | ||
1306 | break; | ||
1307 | case ISDN_P_B_RAW: | ||
1308 | WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ | ||
1309 | WriteHSCX(hscx, IPAC_CCR1, 0x85); | ||
1310 | hscx_cmdr(hscx, 0x41); | ||
1311 | WriteHSCX(hscx, IPAC_MASKB, 0); | ||
1312 | test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); | ||
1313 | break; | ||
1314 | case ISDN_P_B_HDLC: | ||
1315 | WriteHSCX(hscx, IPAC_MODEB, 0x8c); | ||
1316 | WriteHSCX(hscx, IPAC_CCR1, 0x8d); | ||
1317 | hscx_cmdr(hscx, 0x41); | ||
1318 | WriteHSCX(hscx, IPAC_MASKB, 0); | ||
1319 | test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); | ||
1320 | break; | ||
1321 | default: | ||
1322 | pr_info("%s: protocol not known %x\n", hscx->ip->name, | ||
1323 | bprotocol); | ||
1324 | return -ENOPROTOOPT; | ||
1325 | } | ||
1326 | } else | ||
1327 | return -EINVAL; | ||
1328 | hscx->bch.state = bprotocol; | ||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | static int | ||
1333 | hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1334 | { | ||
1335 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1336 | struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); | ||
1337 | int ret = -EINVAL; | ||
1338 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1339 | u32 id; | ||
1340 | u_long flags; | ||
1341 | |||
1342 | switch (hh->prim) { | ||
1343 | case PH_DATA_REQ: | ||
1344 | spin_lock_irqsave(hx->ip->hwlock, flags); | ||
1345 | ret = bchannel_senddata(bch, skb); | ||
1346 | if (ret > 0) { /* direct TX */ | ||
1347 | id = hh->id; /* skb can be freed */ | ||
1348 | ret = 0; | ||
1349 | hscx_fill_fifo(hx); | ||
1350 | spin_unlock_irqrestore(hx->ip->hwlock, flags); | ||
1351 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
1352 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
1353 | } else | ||
1354 | spin_unlock_irqrestore(hx->ip->hwlock, flags); | ||
1355 | return ret; | ||
1356 | case PH_ACTIVATE_REQ: | ||
1357 | spin_lock_irqsave(hx->ip->hwlock, flags); | ||
1358 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
1359 | ret = hscx_mode(hx, ch->protocol); | ||
1360 | else | ||
1361 | ret = 0; | ||
1362 | spin_unlock_irqrestore(hx->ip->hwlock, flags); | ||
1363 | if (!ret) | ||
1364 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
1365 | NULL, GFP_KERNEL); | ||
1366 | break; | ||
1367 | case PH_DEACTIVATE_REQ: | ||
1368 | spin_lock_irqsave(hx->ip->hwlock, flags); | ||
1369 | mISDN_clear_bchannel(bch); | ||
1370 | hscx_mode(hx, ISDN_P_NONE); | ||
1371 | spin_unlock_irqrestore(hx->ip->hwlock, flags); | ||
1372 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
1373 | NULL, GFP_KERNEL); | ||
1374 | ret = 0; | ||
1375 | break; | ||
1376 | default: | ||
1377 | pr_info("%s: %s unknown prim(%x,%x)\n", | ||
1378 | hx->ip->name, __func__, hh->prim, hh->id); | ||
1379 | ret = -EINVAL; | ||
1380 | } | ||
1381 | if (!ret) | ||
1382 | dev_kfree_skb(skb); | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | static int | ||
1387 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
1388 | { | ||
1389 | int ret = 0; | ||
1390 | |||
1391 | switch (cq->op) { | ||
1392 | case MISDN_CTRL_GETOP: | ||
1393 | cq->op = 0; | ||
1394 | break; | ||
1395 | /* Nothing implemented yet */ | ||
1396 | case MISDN_CTRL_FILL_EMPTY: | ||
1397 | default: | ||
1398 | pr_info("%s: unknown Op %x\n", __func__, cq->op); | ||
1399 | ret = -EINVAL; | ||
1400 | break; | ||
1401 | } | ||
1402 | return ret; | ||
1403 | } | ||
1404 | |||
1405 | static int | ||
1406 | hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
1407 | { | ||
1408 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1409 | struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); | ||
1410 | int ret = -EINVAL; | ||
1411 | u_long flags; | ||
1412 | |||
1413 | pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg); | ||
1414 | switch (cmd) { | ||
1415 | case CLOSE_CHANNEL: | ||
1416 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
1417 | if (test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
1418 | spin_lock_irqsave(hx->ip->hwlock, flags); | ||
1419 | mISDN_freebchannel(bch); | ||
1420 | hscx_mode(hx, ISDN_P_NONE); | ||
1421 | spin_unlock_irqrestore(hx->ip->hwlock, flags); | ||
1422 | } else { | ||
1423 | skb_queue_purge(&bch->rqueue); | ||
1424 | bch->rcount = 0; | ||
1425 | } | ||
1426 | ch->protocol = ISDN_P_NONE; | ||
1427 | ch->peer = NULL; | ||
1428 | module_put(hx->ip->owner); | ||
1429 | ret = 0; | ||
1430 | break; | ||
1431 | case CONTROL_CHANNEL: | ||
1432 | ret = channel_bctrl(bch, arg); | ||
1433 | break; | ||
1434 | default: | ||
1435 | pr_info("%s: %s unknown prim(%x)\n", | ||
1436 | hx->ip->name, __func__, cmd); | ||
1437 | } | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | static void | ||
1442 | free_ipac(struct ipac_hw *ipac) | ||
1443 | { | ||
1444 | isac_release(&ipac->isac); | ||
1445 | } | ||
1446 | |||
1447 | static const char *HSCXVer[] = | ||
1448 | {"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", | ||
1449 | "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; | ||
1450 | |||
1451 | |||
1452 | |||
1453 | static void | ||
1454 | hscx_init(struct hscx_hw *hx) | ||
1455 | { | ||
1456 | u8 val; | ||
1457 | |||
1458 | WriteHSCX(hx, IPAC_RAH2, 0xFF); | ||
1459 | WriteHSCX(hx, IPAC_XBCH, 0x00); | ||
1460 | WriteHSCX(hx, IPAC_RLCR, 0x00); | ||
1461 | |||
1462 | if (hx->ip->type & IPAC_TYPE_HSCX) { | ||
1463 | WriteHSCX(hx, IPAC_CCR1, 0x85); | ||
1464 | val = ReadHSCX(hx, HSCX_VSTR); | ||
1465 | pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val); | ||
1466 | if (hx->bch.debug & DEBUG_HW) | ||
1467 | pr_notice("%s: HSCX version %s\n", hx->ip->name, | ||
1468 | HSCXVer[val & 0x0f]); | ||
1469 | } else | ||
1470 | WriteHSCX(hx, IPAC_CCR1, 0x82); | ||
1471 | WriteHSCX(hx, IPAC_CCR2, 0x30); | ||
1472 | WriteHSCX(hx, IPAC_XCCR, 0x07); | ||
1473 | WriteHSCX(hx, IPAC_RCCR, 0x07); | ||
1474 | } | ||
1475 | |||
1476 | static int | ||
1477 | ipac_init(struct ipac_hw *ipac) | ||
1478 | { | ||
1479 | u8 val; | ||
1480 | |||
1481 | if (ipac->type & IPAC_TYPE_HSCX) { | ||
1482 | hscx_init(&ipac->hscx[0]); | ||
1483 | hscx_init(&ipac->hscx[1]); | ||
1484 | val = ReadIPAC(ipac, IPAC_ID); | ||
1485 | } else if (ipac->type & IPAC_TYPE_IPAC) { | ||
1486 | hscx_init(&ipac->hscx[0]); | ||
1487 | hscx_init(&ipac->hscx[1]); | ||
1488 | WriteIPAC(ipac, IPAC_MASK, IPAC__ON); | ||
1489 | val = ReadIPAC(ipac, IPAC_CONF); | ||
1490 | /* conf is default 0, but can be overwritten by card setup */ | ||
1491 | pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name, | ||
1492 | val, ipac->conf); | ||
1493 | WriteIPAC(ipac, IPAC_CONF, ipac->conf); | ||
1494 | val = ReadIPAC(ipac, IPAC_ID); | ||
1495 | if (ipac->hscx[0].bch.debug & DEBUG_HW) | ||
1496 | pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val); | ||
1497 | } | ||
1498 | /* nothing special for IPACX to do here */ | ||
1499 | return isac_init(&ipac->isac); | ||
1500 | } | ||
1501 | |||
1502 | static int | ||
1503 | open_bchannel(struct ipac_hw *ipac, struct channel_req *rq) | ||
1504 | { | ||
1505 | struct bchannel *bch; | ||
1506 | |||
1507 | if (rq->adr.channel > 2) | ||
1508 | return -EINVAL; | ||
1509 | if (rq->protocol == ISDN_P_NONE) | ||
1510 | return -EINVAL; | ||
1511 | bch = &ipac->hscx[rq->adr.channel - 1].bch; | ||
1512 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
1513 | return -EBUSY; /* b-channel can be only open once */ | ||
1514 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | ||
1515 | bch->ch.protocol = rq->protocol; | ||
1516 | rq->ch = &bch->ch; | ||
1517 | return 0; | ||
1518 | } | ||
1519 | |||
1520 | static int | ||
1521 | channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) | ||
1522 | { | ||
1523 | int ret = 0; | ||
1524 | |||
1525 | switch (cq->op) { | ||
1526 | case MISDN_CTRL_GETOP: | ||
1527 | cq->op = MISDN_CTRL_LOOP; | ||
1528 | break; | ||
1529 | case MISDN_CTRL_LOOP: | ||
1530 | /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ | ||
1531 | if (cq->channel < 0 || cq->channel > 3) { | ||
1532 | ret = -EINVAL; | ||
1533 | break; | ||
1534 | } | ||
1535 | ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel); | ||
1536 | break; | ||
1537 | default: | ||
1538 | pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op); | ||
1539 | ret = -EINVAL; | ||
1540 | break; | ||
1541 | } | ||
1542 | return ret; | ||
1543 | } | ||
1544 | |||
1545 | static int | ||
1546 | ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
1547 | { | ||
1548 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1549 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1550 | struct isac_hw *isac = container_of(dch, struct isac_hw, dch); | ||
1551 | struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac); | ||
1552 | struct channel_req *rq; | ||
1553 | int err = 0; | ||
1554 | |||
1555 | pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg); | ||
1556 | switch (cmd) { | ||
1557 | case OPEN_CHANNEL: | ||
1558 | rq = arg; | ||
1559 | if (rq->protocol == ISDN_P_TE_S0) | ||
1560 | err = open_dchannel(isac, rq); | ||
1561 | else | ||
1562 | err = open_bchannel(ipac, rq); | ||
1563 | if (err) | ||
1564 | break; | ||
1565 | if (!try_module_get(ipac->owner)) | ||
1566 | pr_info("%s: cannot get module\n", ipac->name); | ||
1567 | break; | ||
1568 | case CLOSE_CHANNEL: | ||
1569 | pr_debug("%s: dev(%d) close from %p\n", ipac->name, | ||
1570 | dch->dev.id, __builtin_return_address(0)); | ||
1571 | module_put(ipac->owner); | ||
1572 | break; | ||
1573 | case CONTROL_CHANNEL: | ||
1574 | err = channel_ctrl(ipac, arg); | ||
1575 | break; | ||
1576 | default: | ||
1577 | pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd); | ||
1578 | return -EINVAL; | ||
1579 | } | ||
1580 | return err; | ||
1581 | } | ||
1582 | |||
1583 | u32 | ||
1584 | mISDNipac_init(struct ipac_hw *ipac, void *hw) | ||
1585 | { | ||
1586 | u32 ret; | ||
1587 | u8 i; | ||
1588 | |||
1589 | ipac->hw = hw; | ||
1590 | if (ipac->isac.dch.debug & DEBUG_HW) | ||
1591 | pr_notice("%s: ipac type %x\n", ipac->name, ipac->type); | ||
1592 | if (ipac->type & IPAC_TYPE_HSCX) { | ||
1593 | ipac->isac.type = IPAC_TYPE_ISAC; | ||
1594 | ipac->hscx[0].off = 0; | ||
1595 | ipac->hscx[1].off = 0x40; | ||
1596 | ipac->hscx[0].fifo_size = 32; | ||
1597 | ipac->hscx[1].fifo_size = 32; | ||
1598 | } else if (ipac->type & IPAC_TYPE_IPAC) { | ||
1599 | ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC; | ||
1600 | ipac->hscx[0].off = 0; | ||
1601 | ipac->hscx[1].off = 0x40; | ||
1602 | ipac->hscx[0].fifo_size = 64; | ||
1603 | ipac->hscx[1].fifo_size = 64; | ||
1604 | } else if (ipac->type & IPAC_TYPE_IPACX) { | ||
1605 | ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX; | ||
1606 | ipac->hscx[0].off = IPACX_OFF_ICA; | ||
1607 | ipac->hscx[1].off = IPACX_OFF_ICB; | ||
1608 | ipac->hscx[0].fifo_size = 64; | ||
1609 | ipac->hscx[1].fifo_size = 64; | ||
1610 | } else | ||
1611 | return 0; | ||
1612 | |||
1613 | mISDNisac_init(&ipac->isac, hw); | ||
1614 | |||
1615 | ipac->isac.dch.dev.D.ctrl = ipac_dctrl; | ||
1616 | |||
1617 | for (i = 0; i < 2; i++) { | ||
1618 | ipac->hscx[i].bch.nr = i + 1; | ||
1619 | set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); | ||
1620 | list_add(&ipac->hscx[i].bch.ch.list, | ||
1621 | &ipac->isac.dch.dev.bchannels); | ||
1622 | mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM); | ||
1623 | ipac->hscx[i].bch.ch.nr = i + 1; | ||
1624 | ipac->hscx[i].bch.ch.send = &hscx_l2l1; | ||
1625 | ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; | ||
1626 | ipac->hscx[i].bch.hw = hw; | ||
1627 | ipac->hscx[i].ip = ipac; | ||
1628 | /* default values for IOM time slots | ||
1629 | * can be overwriten by card */ | ||
1630 | ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03; | ||
1631 | } | ||
1632 | |||
1633 | ipac->init = ipac_init; | ||
1634 | ipac->release = free_ipac; | ||
1635 | |||
1636 | ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1637 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
1638 | return ret; | ||
1639 | } | ||
1640 | EXPORT_SYMBOL(mISDNipac_init); | ||
1641 | |||
1642 | static int __init | ||
1643 | isac_mod_init(void) | ||
1644 | { | ||
1645 | pr_notice("mISDNipac module version %s\n", ISAC_REV); | ||
1646 | return 0; | ||
1647 | } | ||
1648 | |||
1649 | static void __exit | ||
1650 | isac_mod_cleanup(void) | ||
1651 | { | ||
1652 | pr_notice("mISDNipac module unloaded\n"); | ||
1653 | } | ||
1654 | module_init(isac_mod_init); | ||
1655 | module_exit(isac_mod_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c new file mode 100644 index 000000000000..de352a17673a --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c | |||
@@ -0,0 +1,1726 @@ | |||
1 | /* | ||
2 | * mISDNisar.c ISAR (Siemens PSB 7110) specific functions | ||
3 | * | ||
4 | * Author Karsten Keil (keil@isdn4linux.de) | ||
5 | * | ||
6 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | /* define this to enable static debug messages, if you kernel supports | ||
24 | * dynamic debugging, you should use debugfs for this | ||
25 | */ | ||
26 | /* #define DEBUG */ | ||
27 | |||
28 | #include <linux/delay.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/mISDNhw.h> | ||
31 | #include "isar.h" | ||
32 | |||
33 | #define ISAR_REV "2.1" | ||
34 | |||
35 | MODULE_AUTHOR("Karsten Keil"); | ||
36 | MODULE_LICENSE("GPL v2"); | ||
37 | MODULE_VERSION(ISAR_REV); | ||
38 | |||
39 | #define DEBUG_HW_FIRMWARE_FIFO 0x10000 | ||
40 | |||
41 | static const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; | ||
42 | static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, | ||
43 | 122, 145, 146}; | ||
44 | #define FAXMODCNT 13 | ||
45 | |||
46 | static void isar_setup(struct isar_hw *); | ||
47 | |||
48 | static inline int | ||
49 | waitforHIA(struct isar_hw *isar, int timeout) | ||
50 | { | ||
51 | int t = timeout; | ||
52 | u8 val = isar->read_reg(isar->hw, ISAR_HIA); | ||
53 | |||
54 | while ((val & 1) && t) { | ||
55 | udelay(1); | ||
56 | t--; | ||
57 | val = isar->read_reg(isar->hw, ISAR_HIA); | ||
58 | } | ||
59 | pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); | ||
60 | return timeout; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * send msg to ISAR mailbox | ||
65 | * if msg is NULL use isar->buf | ||
66 | */ | ||
67 | static int | ||
68 | send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) | ||
69 | { | ||
70 | if (!waitforHIA(isar, 1000)) | ||
71 | return 0; | ||
72 | pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); | ||
73 | isar->write_reg(isar->hw, ISAR_CTRL_H, creg); | ||
74 | isar->write_reg(isar->hw, ISAR_CTRL_L, len); | ||
75 | isar->write_reg(isar->hw, ISAR_WADR, 0); | ||
76 | if (!msg) | ||
77 | msg = isar->buf; | ||
78 | if (msg && len) { | ||
79 | isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); | ||
80 | if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { | ||
81 | int l = 0; | ||
82 | |||
83 | while (l < (int)len) { | ||
84 | hex_dump_to_buffer(msg + l, len - l, 32, 1, | ||
85 | isar->log, 256, 1); | ||
86 | pr_debug("%s: %s %02x: %s\n", isar->name, | ||
87 | __func__, l, isar->log); | ||
88 | l += 32; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | isar->write_reg(isar->hw, ISAR_HIS, his); | ||
93 | waitforHIA(isar, 1000); | ||
94 | return 1; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * receive message from ISAR mailbox | ||
99 | * if msg is NULL use isar->buf | ||
100 | */ | ||
101 | static void | ||
102 | rcv_mbox(struct isar_hw *isar, u8 *msg) | ||
103 | { | ||
104 | if (!msg) | ||
105 | msg = isar->buf; | ||
106 | isar->write_reg(isar->hw, ISAR_RADR, 0); | ||
107 | if (msg && isar->clsb) { | ||
108 | isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); | ||
109 | if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { | ||
110 | int l = 0; | ||
111 | |||
112 | while (l < (int)isar->clsb) { | ||
113 | hex_dump_to_buffer(msg + l, isar->clsb - l, 32, | ||
114 | 1, isar->log, 256, 1); | ||
115 | pr_debug("%s: %s %02x: %s\n", isar->name, | ||
116 | __func__, l, isar->log); | ||
117 | l += 32; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | isar->write_reg(isar->hw, ISAR_IIA, 0); | ||
122 | } | ||
123 | |||
124 | static inline void | ||
125 | get_irq_infos(struct isar_hw *isar) | ||
126 | { | ||
127 | isar->iis = isar->read_reg(isar->hw, ISAR_IIS); | ||
128 | isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); | ||
129 | isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); | ||
130 | pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, | ||
131 | isar->iis, isar->cmsb, isar->clsb); | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * poll answer message from ISAR mailbox | ||
136 | * should be used only with ISAR IRQs disabled before DSP was started | ||
137 | * | ||
138 | */ | ||
139 | static int | ||
140 | poll_mbox(struct isar_hw *isar, int maxdelay) | ||
141 | { | ||
142 | int t = maxdelay; | ||
143 | u8 irq; | ||
144 | |||
145 | irq = isar->read_reg(isar->hw, ISAR_IRQBIT); | ||
146 | while (t && !(irq & ISAR_IRQSTA)) { | ||
147 | udelay(1); | ||
148 | t--; | ||
149 | } | ||
150 | if (t) { | ||
151 | get_irq_infos(isar); | ||
152 | rcv_mbox(isar, NULL); | ||
153 | } | ||
154 | pr_debug("%s: pulled %d bytes after %d us\n", | ||
155 | isar->name, isar->clsb, maxdelay - t); | ||
156 | return t; | ||
157 | } | ||
158 | |||
159 | static int | ||
160 | ISARVersion(struct isar_hw *isar) | ||
161 | { | ||
162 | int ver; | ||
163 | |||
164 | /* disable ISAR IRQ */ | ||
165 | isar->write_reg(isar->hw, ISAR_IRQBIT, 0); | ||
166 | isar->buf[0] = ISAR_MSG_HWVER; | ||
167 | isar->buf[1] = 0; | ||
168 | isar->buf[2] = 1; | ||
169 | if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) | ||
170 | return -1; | ||
171 | if (!poll_mbox(isar, 1000)) | ||
172 | return -2; | ||
173 | if (isar->iis == ISAR_IIS_VNR) { | ||
174 | if (isar->clsb == 1) { | ||
175 | ver = isar->buf[0] & 0xf; | ||
176 | return ver; | ||
177 | } | ||
178 | return -3; | ||
179 | } | ||
180 | return -4; | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | load_firmware(struct isar_hw *isar, const u8 *buf, int size) | ||
185 | { | ||
186 | u32 saved_debug = isar->ch[0].bch.debug; | ||
187 | int ret, cnt; | ||
188 | u8 nom, noc; | ||
189 | u16 left, val, *sp = (u16 *)buf; | ||
190 | u8 *mp; | ||
191 | u_long flags; | ||
192 | |||
193 | struct { | ||
194 | u16 sadr; | ||
195 | u16 len; | ||
196 | u16 d_key; | ||
197 | } blk_head; | ||
198 | |||
199 | if (1 != isar->version) { | ||
200 | pr_err("%s: ISAR wrong version %d firmware download aborted\n", | ||
201 | isar->name, isar->version); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) | ||
205 | isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; | ||
206 | pr_debug("%s: load firmware %d words (%d bytes)\n", | ||
207 | isar->name, size/2, size); | ||
208 | cnt = 0; | ||
209 | size /= 2; | ||
210 | /* disable ISAR IRQ */ | ||
211 | spin_lock_irqsave(isar->hwlock, flags); | ||
212 | isar->write_reg(isar->hw, ISAR_IRQBIT, 0); | ||
213 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
214 | while (cnt < size) { | ||
215 | blk_head.sadr = le16_to_cpu(*sp++); | ||
216 | blk_head.len = le16_to_cpu(*sp++); | ||
217 | blk_head.d_key = le16_to_cpu(*sp++); | ||
218 | cnt += 3; | ||
219 | pr_debug("ISAR firmware block (%#x,%d,%#x)\n", | ||
220 | blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); | ||
221 | left = blk_head.len; | ||
222 | if (cnt + left > size) { | ||
223 | pr_info("%s: firmware error have %d need %d words\n", | ||
224 | isar->name, size, cnt + left); | ||
225 | ret = -EINVAL; | ||
226 | goto reterrflg; | ||
227 | } | ||
228 | spin_lock_irqsave(isar->hwlock, flags); | ||
229 | if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, | ||
230 | 0, NULL)) { | ||
231 | pr_info("ISAR send_mbox dkey failed\n"); | ||
232 | ret = -ETIME; | ||
233 | goto reterror; | ||
234 | } | ||
235 | if (!poll_mbox(isar, 1000)) { | ||
236 | pr_warning("ISAR poll_mbox dkey failed\n"); | ||
237 | ret = -ETIME; | ||
238 | goto reterror; | ||
239 | } | ||
240 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
241 | if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { | ||
242 | pr_info("ISAR wrong dkey response (%x,%x,%x)\n", | ||
243 | isar->iis, isar->cmsb, isar->clsb); | ||
244 | ret = 1; | ||
245 | goto reterrflg; | ||
246 | } | ||
247 | while (left > 0) { | ||
248 | if (left > 126) | ||
249 | noc = 126; | ||
250 | else | ||
251 | noc = left; | ||
252 | nom = (2 * noc) + 3; | ||
253 | mp = isar->buf; | ||
254 | /* the ISAR is big endian */ | ||
255 | *mp++ = blk_head.sadr >> 8; | ||
256 | *mp++ = blk_head.sadr & 0xFF; | ||
257 | left -= noc; | ||
258 | cnt += noc; | ||
259 | *mp++ = noc; | ||
260 | pr_debug("%s: load %3d words at %04x\n", isar->name, | ||
261 | noc, blk_head.sadr); | ||
262 | blk_head.sadr += noc; | ||
263 | while (noc) { | ||
264 | val = le16_to_cpu(*sp++); | ||
265 | *mp++ = val >> 8; | ||
266 | *mp++ = val & 0xFF;; | ||
267 | noc--; | ||
268 | } | ||
269 | spin_lock_irqsave(isar->hwlock, flags); | ||
270 | if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { | ||
271 | pr_info("ISAR send_mbox prog failed\n"); | ||
272 | ret = -ETIME; | ||
273 | goto reterror; | ||
274 | } | ||
275 | if (!poll_mbox(isar, 1000)) { | ||
276 | pr_info("ISAR poll_mbox prog failed\n"); | ||
277 | ret = -ETIME; | ||
278 | goto reterror; | ||
279 | } | ||
280 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
281 | if ((isar->iis != ISAR_IIS_FIRM) || | ||
282 | isar->cmsb || isar->clsb) { | ||
283 | pr_info("ISAR wrong prog response (%x,%x,%x)\n", | ||
284 | isar->iis, isar->cmsb, isar->clsb); | ||
285 | ret = -EIO; | ||
286 | goto reterrflg; | ||
287 | } | ||
288 | } | ||
289 | pr_debug("%s: ISAR firmware block %d words loaded\n", | ||
290 | isar->name, blk_head.len); | ||
291 | } | ||
292 | isar->ch[0].bch.debug = saved_debug; | ||
293 | /* 10ms delay */ | ||
294 | cnt = 10; | ||
295 | while (cnt--) | ||
296 | mdelay(1); | ||
297 | isar->buf[0] = 0xff; | ||
298 | isar->buf[1] = 0xfe; | ||
299 | isar->bstat = 0; | ||
300 | spin_lock_irqsave(isar->hwlock, flags); | ||
301 | if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { | ||
302 | pr_info("ISAR send_mbox start dsp failed\n"); | ||
303 | ret = -ETIME; | ||
304 | goto reterror; | ||
305 | } | ||
306 | if (!poll_mbox(isar, 1000)) { | ||
307 | pr_info("ISAR poll_mbox start dsp failed\n"); | ||
308 | ret = -ETIME; | ||
309 | goto reterror; | ||
310 | } | ||
311 | if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { | ||
312 | pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", | ||
313 | isar->iis, isar->cmsb, isar->clsb); | ||
314 | ret = -EIO; | ||
315 | goto reterror; | ||
316 | } else | ||
317 | pr_debug("%s: ISAR start dsp success\n", isar->name); | ||
318 | |||
319 | /* NORMAL mode entered */ | ||
320 | /* Enable IRQs of ISAR */ | ||
321 | isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); | ||
322 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
323 | cnt = 1000; /* max 1s */ | ||
324 | while ((!isar->bstat) && cnt) { | ||
325 | mdelay(1); | ||
326 | cnt--; | ||
327 | } | ||
328 | if (!cnt) { | ||
329 | pr_info("ISAR no general status event received\n"); | ||
330 | ret = -ETIME; | ||
331 | goto reterrflg; | ||
332 | } else | ||
333 | pr_debug("%s: ISAR general status event %x\n", | ||
334 | isar->name, isar->bstat); | ||
335 | /* 10ms delay */ | ||
336 | cnt = 10; | ||
337 | while (cnt--) | ||
338 | mdelay(1); | ||
339 | isar->iis = 0; | ||
340 | spin_lock_irqsave(isar->hwlock, flags); | ||
341 | if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { | ||
342 | pr_info("ISAR send_mbox self tst failed\n"); | ||
343 | ret = -ETIME; | ||
344 | goto reterror; | ||
345 | } | ||
346 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
347 | cnt = 10000; /* max 100 ms */ | ||
348 | while ((isar->iis != ISAR_IIS_DIAG) && cnt) { | ||
349 | udelay(10); | ||
350 | cnt--; | ||
351 | } | ||
352 | mdelay(1); | ||
353 | if (!cnt) { | ||
354 | pr_info("ISAR no self tst response\n"); | ||
355 | ret = -ETIME; | ||
356 | goto reterrflg; | ||
357 | } | ||
358 | if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) | ||
359 | && (isar->buf[0] == 0)) | ||
360 | pr_debug("%s: ISAR selftest OK\n", isar->name); | ||
361 | else { | ||
362 | pr_info("ISAR selftest not OK %x/%x/%x\n", | ||
363 | isar->cmsb, isar->clsb, isar->buf[0]); | ||
364 | ret = -EIO; | ||
365 | goto reterrflg; | ||
366 | } | ||
367 | spin_lock_irqsave(isar->hwlock, flags); | ||
368 | isar->iis = 0; | ||
369 | if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { | ||
370 | pr_info("ISAR RQST SVN failed\n"); | ||
371 | ret = -ETIME; | ||
372 | goto reterror; | ||
373 | } | ||
374 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
375 | cnt = 30000; /* max 300 ms */ | ||
376 | while ((isar->iis != ISAR_IIS_DIAG) && cnt) { | ||
377 | udelay(10); | ||
378 | cnt--; | ||
379 | } | ||
380 | mdelay(1); | ||
381 | if (!cnt) { | ||
382 | pr_info("ISAR no SVN response\n"); | ||
383 | ret = -ETIME; | ||
384 | goto reterrflg; | ||
385 | } else { | ||
386 | if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { | ||
387 | pr_notice("%s: ISAR software version %#x\n", | ||
388 | isar->name, isar->buf[0]); | ||
389 | } else { | ||
390 | pr_info("%s: ISAR wrong swver response (%x,%x)" | ||
391 | " cnt(%d)\n", isar->name, isar->cmsb, | ||
392 | isar->clsb, cnt); | ||
393 | ret = -EIO; | ||
394 | goto reterrflg; | ||
395 | } | ||
396 | } | ||
397 | spin_lock_irqsave(isar->hwlock, flags); | ||
398 | isar_setup(isar); | ||
399 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
400 | ret = 0; | ||
401 | reterrflg: | ||
402 | spin_lock_irqsave(isar->hwlock, flags); | ||
403 | reterror: | ||
404 | isar->ch[0].bch.debug = saved_debug; | ||
405 | if (ret) | ||
406 | /* disable ISAR IRQ */ | ||
407 | isar->write_reg(isar->hw, ISAR_IRQBIT, 0); | ||
408 | spin_unlock_irqrestore(isar->hwlock, flags); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static inline void | ||
413 | deliver_status(struct isar_ch *ch, int status) | ||
414 | { | ||
415 | pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); | ||
416 | _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); | ||
417 | } | ||
418 | |||
419 | static inline void | ||
420 | isar_rcv_frame(struct isar_ch *ch) | ||
421 | { | ||
422 | u8 *ptr; | ||
423 | |||
424 | if (!ch->is->clsb) { | ||
425 | pr_debug("%s; ISAR zero len frame\n", ch->is->name); | ||
426 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
427 | return; | ||
428 | } | ||
429 | switch (ch->bch.state) { | ||
430 | case ISDN_P_NONE: | ||
431 | pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", | ||
432 | ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); | ||
433 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
434 | break; | ||
435 | case ISDN_P_B_RAW: | ||
436 | case ISDN_P_B_L2DTMF: | ||
437 | case ISDN_P_B_MODEM_ASYNC: | ||
438 | if (!ch->bch.rx_skb) { | ||
439 | ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, | ||
440 | GFP_ATOMIC); | ||
441 | if (unlikely(!ch->bch.rx_skb)) { | ||
442 | pr_info("%s: B receive out of memory\n", | ||
443 | ch->is->name); | ||
444 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
445 | break; | ||
446 | } | ||
447 | } | ||
448 | rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); | ||
449 | recv_Bchannel(&ch->bch, 0); | ||
450 | break; | ||
451 | case ISDN_P_B_HDLC: | ||
452 | if (!ch->bch.rx_skb) { | ||
453 | ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, | ||
454 | GFP_ATOMIC); | ||
455 | if (unlikely(!ch->bch.rx_skb)) { | ||
456 | pr_info("%s: B receive out of memory\n", | ||
457 | ch->is->name); | ||
458 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | if ((ch->bch.rx_skb->len + ch->is->clsb) > | ||
463 | (ch->bch.maxlen + 2)) { | ||
464 | pr_debug("%s: incoming packet too large\n", | ||
465 | ch->is->name); | ||
466 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
467 | skb_trim(ch->bch.rx_skb, 0); | ||
468 | break; | ||
469 | } | ||
470 | if (ch->is->cmsb & HDLC_ERROR) { | ||
471 | pr_debug("%s: ISAR frame error %x len %d\n", | ||
472 | ch->is->name, ch->is->cmsb, ch->is->clsb); | ||
473 | #ifdef ERROR_STATISTIC | ||
474 | if (ch->is->cmsb & HDLC_ERR_RER) | ||
475 | ch->bch.err_inv++; | ||
476 | if (ch->is->cmsb & HDLC_ERR_CER) | ||
477 | ch->bch.err_crc++; | ||
478 | #endif | ||
479 | skb_trim(ch->bch.rx_skb, 0); | ||
480 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
481 | break; | ||
482 | } | ||
483 | if (ch->is->cmsb & HDLC_FSD) | ||
484 | skb_trim(ch->bch.rx_skb, 0); | ||
485 | ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); | ||
486 | rcv_mbox(ch->is, ptr); | ||
487 | if (ch->is->cmsb & HDLC_FED) { | ||
488 | if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ | ||
489 | pr_debug("%s: ISAR frame to short %d\n", | ||
490 | ch->is->name, ch->bch.rx_skb->len); | ||
491 | skb_trim(ch->bch.rx_skb, 0); | ||
492 | break; | ||
493 | } | ||
494 | skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); | ||
495 | recv_Bchannel(&ch->bch, 0); | ||
496 | } | ||
497 | break; | ||
498 | case ISDN_P_B_T30_FAX: | ||
499 | if (ch->state != STFAX_ACTIV) { | ||
500 | pr_debug("%s: isar_rcv_frame: not ACTIV\n", | ||
501 | ch->is->name); | ||
502 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
503 | if (ch->bch.rx_skb) | ||
504 | skb_trim(ch->bch.rx_skb, 0); | ||
505 | break; | ||
506 | } | ||
507 | if (!ch->bch.rx_skb) { | ||
508 | ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, | ||
509 | GFP_ATOMIC); | ||
510 | if (unlikely(!ch->bch.rx_skb)) { | ||
511 | pr_info("%s: B receive out of memory\n", | ||
512 | __func__); | ||
513 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
514 | break; | ||
515 | } | ||
516 | } | ||
517 | if (ch->cmd == PCTRL_CMD_FRM) { | ||
518 | rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); | ||
519 | pr_debug("%s: isar_rcv_frame: %d\n", | ||
520 | ch->is->name, ch->bch.rx_skb->len); | ||
521 | if (ch->is->cmsb & SART_NMD) { /* ABORT */ | ||
522 | pr_debug("%s: isar_rcv_frame: no more data\n", | ||
523 | ch->is->name); | ||
524 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
525 | send_mbox(ch->is, SET_DPS(ch->dpath) | | ||
526 | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, | ||
527 | 0, NULL); | ||
528 | ch->state = STFAX_ESCAPE; | ||
529 | /* set_skb_flag(skb, DF_NOMOREDATA); */ | ||
530 | } | ||
531 | recv_Bchannel(&ch->bch, 0); | ||
532 | if (ch->is->cmsb & SART_NMD) | ||
533 | deliver_status(ch, HW_MOD_NOCARR); | ||
534 | break; | ||
535 | } | ||
536 | if (ch->cmd != PCTRL_CMD_FRH) { | ||
537 | pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", | ||
538 | ch->is->name, ch->cmd); | ||
539 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
540 | if (ch->bch.rx_skb) | ||
541 | skb_trim(ch->bch.rx_skb, 0); | ||
542 | break; | ||
543 | } | ||
544 | /* PCTRL_CMD_FRH */ | ||
545 | if ((ch->bch.rx_skb->len + ch->is->clsb) > | ||
546 | (ch->bch.maxlen + 2)) { | ||
547 | pr_info("%s: %s incoming packet too large\n", | ||
548 | ch->is->name, __func__); | ||
549 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
550 | skb_trim(ch->bch.rx_skb, 0); | ||
551 | break; | ||
552 | } else if (ch->is->cmsb & HDLC_ERROR) { | ||
553 | pr_info("%s: ISAR frame error %x len %d\n", | ||
554 | ch->is->name, ch->is->cmsb, ch->is->clsb); | ||
555 | skb_trim(ch->bch.rx_skb, 0); | ||
556 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
557 | break; | ||
558 | } | ||
559 | if (ch->is->cmsb & HDLC_FSD) | ||
560 | skb_trim(ch->bch.rx_skb, 0); | ||
561 | ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); | ||
562 | rcv_mbox(ch->is, ptr); | ||
563 | if (ch->is->cmsb & HDLC_FED) { | ||
564 | if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ | ||
565 | pr_info("%s: ISAR frame to short %d\n", | ||
566 | ch->is->name, ch->bch.rx_skb->len); | ||
567 | skb_trim(ch->bch.rx_skb, 0); | ||
568 | break; | ||
569 | } | ||
570 | skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); | ||
571 | recv_Bchannel(&ch->bch, 0); | ||
572 | } | ||
573 | if (ch->is->cmsb & SART_NMD) { /* ABORT */ | ||
574 | pr_debug("%s: isar_rcv_frame: no more data\n", | ||
575 | ch->is->name); | ||
576 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
577 | if (ch->bch.rx_skb) | ||
578 | skb_trim(ch->bch.rx_skb, 0); | ||
579 | send_mbox(ch->is, SET_DPS(ch->dpath) | | ||
580 | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); | ||
581 | ch->state = STFAX_ESCAPE; | ||
582 | deliver_status(ch, HW_MOD_NOCARR); | ||
583 | } | ||
584 | break; | ||
585 | default: | ||
586 | pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); | ||
587 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
588 | break; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | static void | ||
593 | isar_fill_fifo(struct isar_ch *ch) | ||
594 | { | ||
595 | int count; | ||
596 | u8 msb; | ||
597 | u8 *ptr; | ||
598 | |||
599 | pr_debug("%s: ch%d tx_skb %p tx_idx %d\n", | ||
600 | ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx); | ||
601 | if (!ch->bch.tx_skb) | ||
602 | return; | ||
603 | count = ch->bch.tx_skb->len - ch->bch.tx_idx; | ||
604 | if (count <= 0) | ||
605 | return; | ||
606 | if (!(ch->is->bstat & | ||
607 | (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) | ||
608 | return; | ||
609 | if (count > ch->mml) { | ||
610 | msb = 0; | ||
611 | count = ch->mml; | ||
612 | } else { | ||
613 | msb = HDLC_FED; | ||
614 | } | ||
615 | ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; | ||
616 | if (!ch->bch.tx_idx) { | ||
617 | pr_debug("%s: frame start\n", ch->is->name); | ||
618 | if ((ch->bch.state == ISDN_P_B_T30_FAX) && | ||
619 | (ch->cmd == PCTRL_CMD_FTH)) { | ||
620 | if (count > 1) { | ||
621 | if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { | ||
622 | /* last frame */ | ||
623 | test_and_set_bit(FLG_LASTDATA, | ||
624 | &ch->bch.Flags); | ||
625 | pr_debug("%s: set LASTDATA\n", | ||
626 | ch->is->name); | ||
627 | if (msb == HDLC_FED) | ||
628 | test_and_set_bit(FLG_DLEETX, | ||
629 | &ch->bch.Flags); | ||
630 | } | ||
631 | } | ||
632 | } | ||
633 | msb |= HDLC_FST; | ||
634 | } | ||
635 | ch->bch.tx_idx += count; | ||
636 | switch (ch->bch.state) { | ||
637 | case ISDN_P_NONE: | ||
638 | pr_info("%s: wrong protocol 0\n", __func__); | ||
639 | break; | ||
640 | case ISDN_P_B_RAW: | ||
641 | case ISDN_P_B_L2DTMF: | ||
642 | case ISDN_P_B_MODEM_ASYNC: | ||
643 | send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, | ||
644 | 0, count, ptr); | ||
645 | break; | ||
646 | case ISDN_P_B_HDLC: | ||
647 | send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, | ||
648 | msb, count, ptr); | ||
649 | break; | ||
650 | case ISDN_P_B_T30_FAX: | ||
651 | if (ch->state != STFAX_ACTIV) | ||
652 | pr_debug("%s: not ACTIV\n", ch->is->name); | ||
653 | else if (ch->cmd == PCTRL_CMD_FTH) | ||
654 | send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, | ||
655 | msb, count, ptr); | ||
656 | else if (ch->cmd == PCTRL_CMD_FTM) | ||
657 | send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, | ||
658 | 0, count, ptr); | ||
659 | else | ||
660 | pr_debug("%s: not FTH/FTM\n", ch->is->name); | ||
661 | break; | ||
662 | default: | ||
663 | pr_info("%s: protocol(%x) error\n", | ||
664 | __func__, ch->bch.state); | ||
665 | break; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | static inline struct isar_ch * | ||
670 | sel_bch_isar(struct isar_hw *isar, u8 dpath) | ||
671 | { | ||
672 | struct isar_ch *base = &isar->ch[0]; | ||
673 | |||
674 | if ((!dpath) || (dpath > 2)) | ||
675 | return NULL; | ||
676 | if (base->dpath == dpath) | ||
677 | return base; | ||
678 | base++; | ||
679 | if (base->dpath == dpath) | ||
680 | return base; | ||
681 | return NULL; | ||
682 | } | ||
683 | |||
684 | static void | ||
685 | send_next(struct isar_ch *ch) | ||
686 | { | ||
687 | pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n", | ||
688 | ch->is->name, __func__, ch->bch.nr, | ||
689 | ch->bch.tx_skb, ch->bch.tx_idx); | ||
690 | if (ch->bch.state == ISDN_P_B_T30_FAX) { | ||
691 | if (ch->cmd == PCTRL_CMD_FTH) { | ||
692 | if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { | ||
693 | pr_debug("set NMD_DATA\n"); | ||
694 | test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); | ||
695 | } | ||
696 | } else if (ch->cmd == PCTRL_CMD_FTM) { | ||
697 | if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { | ||
698 | test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); | ||
699 | test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | if (ch->bch.tx_skb) { | ||
704 | /* send confirm, on trans, free on hdlc. */ | ||
705 | if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags)) | ||
706 | confirm_Bsend(&ch->bch); | ||
707 | dev_kfree_skb(ch->bch.tx_skb); | ||
708 | } | ||
709 | if (get_next_bframe(&ch->bch)) | ||
710 | isar_fill_fifo(ch); | ||
711 | else { | ||
712 | if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { | ||
713 | if (test_and_clear_bit(FLG_LASTDATA, | ||
714 | &ch->bch.Flags)) { | ||
715 | if (test_and_clear_bit(FLG_NMD_DATA, | ||
716 | &ch->bch.Flags)) { | ||
717 | u8 zd = 0; | ||
718 | send_mbox(ch->is, SET_DPS(ch->dpath) | | ||
719 | ISAR_HIS_SDATA, 0x01, 1, &zd); | ||
720 | } | ||
721 | test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); | ||
722 | } else { | ||
723 | deliver_status(ch, HW_MOD_CONNECT); | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | |||
729 | static void | ||
730 | check_send(struct isar_hw *isar, u8 rdm) | ||
731 | { | ||
732 | struct isar_ch *ch; | ||
733 | |||
734 | pr_debug("%s: rdm %x\n", isar->name, rdm); | ||
735 | if (rdm & BSTAT_RDM1) { | ||
736 | ch = sel_bch_isar(isar, 1); | ||
737 | if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { | ||
738 | if (ch->bch.tx_skb && (ch->bch.tx_skb->len > | ||
739 | ch->bch.tx_idx)) | ||
740 | isar_fill_fifo(ch); | ||
741 | else | ||
742 | send_next(ch); | ||
743 | } | ||
744 | } | ||
745 | if (rdm & BSTAT_RDM2) { | ||
746 | ch = sel_bch_isar(isar, 2); | ||
747 | if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { | ||
748 | if (ch->bch.tx_skb && (ch->bch.tx_skb->len > | ||
749 | ch->bch.tx_idx)) | ||
750 | isar_fill_fifo(ch); | ||
751 | else | ||
752 | send_next(ch); | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | |||
757 | const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", | ||
758 | "300", "600", "1200", "2400", "4800", "7200", | ||
759 | "9600nt", "9600t", "12000", "14400", "WRONG"}; | ||
760 | const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", | ||
761 | "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; | ||
762 | |||
763 | static void | ||
764 | isar_pump_status_rsp(struct isar_ch *ch) { | ||
765 | u8 ril = ch->is->buf[0]; | ||
766 | u8 rim; | ||
767 | |||
768 | if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) | ||
769 | return; | ||
770 | if (ril > 14) { | ||
771 | pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); | ||
772 | ril = 15; | ||
773 | } | ||
774 | switch (ch->is->buf[1]) { | ||
775 | case 0: | ||
776 | rim = 0; | ||
777 | break; | ||
778 | case 0x20: | ||
779 | rim = 2; | ||
780 | break; | ||
781 | case 0x40: | ||
782 | rim = 3; | ||
783 | break; | ||
784 | case 0x41: | ||
785 | rim = 4; | ||
786 | break; | ||
787 | case 0x51: | ||
788 | rim = 5; | ||
789 | break; | ||
790 | case 0x61: | ||
791 | rim = 6; | ||
792 | break; | ||
793 | case 0x71: | ||
794 | rim = 7; | ||
795 | break; | ||
796 | case 0x82: | ||
797 | rim = 8; | ||
798 | break; | ||
799 | case 0x92: | ||
800 | rim = 9; | ||
801 | break; | ||
802 | case 0xa2: | ||
803 | rim = 10; | ||
804 | break; | ||
805 | default: | ||
806 | rim = 1; | ||
807 | break; | ||
808 | } | ||
809 | sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); | ||
810 | pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); | ||
811 | } | ||
812 | |||
813 | static void | ||
814 | isar_pump_statev_modem(struct isar_ch *ch, u8 devt) { | ||
815 | u8 dps = SET_DPS(ch->dpath); | ||
816 | |||
817 | switch (devt) { | ||
818 | case PSEV_10MS_TIMER: | ||
819 | pr_debug("%s: pump stev TIMER\n", ch->is->name); | ||
820 | break; | ||
821 | case PSEV_CON_ON: | ||
822 | pr_debug("%s: pump stev CONNECT\n", ch->is->name); | ||
823 | deliver_status(ch, HW_MOD_CONNECT); | ||
824 | break; | ||
825 | case PSEV_CON_OFF: | ||
826 | pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); | ||
827 | send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); | ||
828 | deliver_status(ch, HW_MOD_NOCARR); | ||
829 | break; | ||
830 | case PSEV_V24_OFF: | ||
831 | pr_debug("%s: pump stev V24 OFF\n", ch->is->name); | ||
832 | break; | ||
833 | case PSEV_CTS_ON: | ||
834 | pr_debug("%s: pump stev CTS ON\n", ch->is->name); | ||
835 | break; | ||
836 | case PSEV_CTS_OFF: | ||
837 | pr_debug("%s pump stev CTS OFF\n", ch->is->name); | ||
838 | break; | ||
839 | case PSEV_DCD_ON: | ||
840 | pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); | ||
841 | test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); | ||
842 | send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); | ||
843 | break; | ||
844 | case PSEV_DCD_OFF: | ||
845 | pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); | ||
846 | break; | ||
847 | case PSEV_DSR_ON: | ||
848 | pr_debug("%s: pump stev DSR ON\n", ch->is->name); | ||
849 | break; | ||
850 | case PSEV_DSR_OFF: | ||
851 | pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); | ||
852 | break; | ||
853 | case PSEV_REM_RET: | ||
854 | pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); | ||
855 | break; | ||
856 | case PSEV_REM_REN: | ||
857 | pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); | ||
858 | break; | ||
859 | case PSEV_GSTN_CLR: | ||
860 | pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); | ||
861 | break; | ||
862 | default: | ||
863 | pr_info("u%s: nknown pump stev %x\n", ch->is->name, devt); | ||
864 | break; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | static void | ||
869 | isar_pump_statev_fax(struct isar_ch *ch, u8 devt) { | ||
870 | u8 dps = SET_DPS(ch->dpath); | ||
871 | u8 p1; | ||
872 | |||
873 | switch (devt) { | ||
874 | case PSEV_10MS_TIMER: | ||
875 | pr_debug("%s: pump stev TIMER\n", ch->is->name); | ||
876 | break; | ||
877 | case PSEV_RSP_READY: | ||
878 | pr_debug("%s: pump stev RSP_READY\n", ch->is->name); | ||
879 | ch->state = STFAX_READY; | ||
880 | deliver_status(ch, HW_MOD_READY); | ||
881 | #ifdef AUTOCON | ||
882 | if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) | ||
883 | isar_pump_cmd(bch, HW_MOD_FRH, 3); | ||
884 | else | ||
885 | isar_pump_cmd(bch, HW_MOD_FTH, 3); | ||
886 | #endif | ||
887 | break; | ||
888 | case PSEV_LINE_TX_H: | ||
889 | if (ch->state == STFAX_LINE) { | ||
890 | pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); | ||
891 | ch->state = STFAX_CONT; | ||
892 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
893 | PCTRL_CMD_CONT, 0, NULL); | ||
894 | } else { | ||
895 | pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", | ||
896 | ch->is->name, ch->state); | ||
897 | } | ||
898 | break; | ||
899 | case PSEV_LINE_RX_H: | ||
900 | if (ch->state == STFAX_LINE) { | ||
901 | pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); | ||
902 | ch->state = STFAX_CONT; | ||
903 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
904 | PCTRL_CMD_CONT, 0, NULL); | ||
905 | } else { | ||
906 | pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", | ||
907 | ch->is->name, ch->state); | ||
908 | } | ||
909 | break; | ||
910 | case PSEV_LINE_TX_B: | ||
911 | if (ch->state == STFAX_LINE) { | ||
912 | pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); | ||
913 | ch->state = STFAX_CONT; | ||
914 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
915 | PCTRL_CMD_CONT, 0, NULL); | ||
916 | } else { | ||
917 | pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", | ||
918 | ch->is->name, ch->state); | ||
919 | } | ||
920 | break; | ||
921 | case PSEV_LINE_RX_B: | ||
922 | if (ch->state == STFAX_LINE) { | ||
923 | pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); | ||
924 | ch->state = STFAX_CONT; | ||
925 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
926 | PCTRL_CMD_CONT, 0, NULL); | ||
927 | } else { | ||
928 | pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", | ||
929 | ch->is->name, ch->state); | ||
930 | } | ||
931 | break; | ||
932 | case PSEV_RSP_CONN: | ||
933 | if (ch->state == STFAX_CONT) { | ||
934 | pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); | ||
935 | ch->state = STFAX_ACTIV; | ||
936 | test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); | ||
937 | send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); | ||
938 | if (ch->cmd == PCTRL_CMD_FTH) { | ||
939 | int delay = (ch->mod == 3) ? 1000 : 200; | ||
940 | /* 1s (200 ms) Flags before data */ | ||
941 | if (test_and_set_bit(FLG_FTI_RUN, | ||
942 | &ch->bch.Flags)) | ||
943 | del_timer(&ch->ftimer); | ||
944 | ch->ftimer.expires = | ||
945 | jiffies + ((delay * HZ)/1000); | ||
946 | test_and_set_bit(FLG_LL_CONN, | ||
947 | &ch->bch.Flags); | ||
948 | add_timer(&ch->ftimer); | ||
949 | } else { | ||
950 | deliver_status(ch, HW_MOD_CONNECT); | ||
951 | } | ||
952 | } else { | ||
953 | pr_debug("%s: pump stev RSP_CONN wrong st %x\n", | ||
954 | ch->is->name, ch->state); | ||
955 | } | ||
956 | break; | ||
957 | case PSEV_FLAGS_DET: | ||
958 | pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); | ||
959 | break; | ||
960 | case PSEV_RSP_DISC: | ||
961 | pr_debug("%s: pump stev RSP_DISC state(%d)\n", | ||
962 | ch->is->name, ch->state); | ||
963 | if (ch->state == STFAX_ESCAPE) { | ||
964 | p1 = 5; | ||
965 | switch (ch->newcmd) { | ||
966 | case 0: | ||
967 | ch->state = STFAX_READY; | ||
968 | break; | ||
969 | case PCTRL_CMD_FTM: | ||
970 | p1 = 2; | ||
971 | case PCTRL_CMD_FTH: | ||
972 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
973 | PCTRL_CMD_SILON, 1, &p1); | ||
974 | ch->state = STFAX_SILDET; | ||
975 | break; | ||
976 | case PCTRL_CMD_FRH: | ||
977 | case PCTRL_CMD_FRM: | ||
978 | ch->mod = ch->newmod; | ||
979 | p1 = ch->newmod; | ||
980 | ch->newmod = 0; | ||
981 | ch->cmd = ch->newcmd; | ||
982 | ch->newcmd = 0; | ||
983 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
984 | ch->cmd, 1, &p1); | ||
985 | ch->state = STFAX_LINE; | ||
986 | ch->try_mod = 3; | ||
987 | break; | ||
988 | default: | ||
989 | pr_debug("%s: RSP_DISC unknown newcmd %x\n", | ||
990 | ch->is->name, ch->newcmd); | ||
991 | break; | ||
992 | } | ||
993 | } else if (ch->state == STFAX_ACTIV) { | ||
994 | if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) | ||
995 | deliver_status(ch, HW_MOD_OK); | ||
996 | else if (ch->cmd == PCTRL_CMD_FRM) | ||
997 | deliver_status(ch, HW_MOD_NOCARR); | ||
998 | else | ||
999 | deliver_status(ch, HW_MOD_FCERROR); | ||
1000 | ch->state = STFAX_READY; | ||
1001 | } else if (ch->state != STFAX_SILDET) { | ||
1002 | /* ignore in STFAX_SILDET */ | ||
1003 | ch->state = STFAX_READY; | ||
1004 | deliver_status(ch, HW_MOD_FCERROR); | ||
1005 | } | ||
1006 | break; | ||
1007 | case PSEV_RSP_SILDET: | ||
1008 | pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); | ||
1009 | if (ch->state == STFAX_SILDET) { | ||
1010 | ch->mod = ch->newmod; | ||
1011 | p1 = ch->newmod; | ||
1012 | ch->newmod = 0; | ||
1013 | ch->cmd = ch->newcmd; | ||
1014 | ch->newcmd = 0; | ||
1015 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
1016 | ch->cmd, 1, &p1); | ||
1017 | ch->state = STFAX_LINE; | ||
1018 | ch->try_mod = 3; | ||
1019 | } | ||
1020 | break; | ||
1021 | case PSEV_RSP_SILOFF: | ||
1022 | pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); | ||
1023 | break; | ||
1024 | case PSEV_RSP_FCERR: | ||
1025 | if (ch->state == STFAX_LINE) { | ||
1026 | pr_debug("%s: pump stev RSP_FCERR try %d\n", | ||
1027 | ch->is->name, ch->try_mod); | ||
1028 | if (ch->try_mod--) { | ||
1029 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, | ||
1030 | ch->cmd, 1, &ch->mod); | ||
1031 | break; | ||
1032 | } | ||
1033 | } | ||
1034 | pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); | ||
1035 | ch->state = STFAX_ESCAPE; | ||
1036 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, | ||
1037 | 0, NULL); | ||
1038 | deliver_status(ch, HW_MOD_FCERROR); | ||
1039 | break; | ||
1040 | default: | ||
1041 | break; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | void | ||
1046 | mISDNisar_irq(struct isar_hw *isar) | ||
1047 | { | ||
1048 | struct isar_ch *ch; | ||
1049 | |||
1050 | get_irq_infos(isar); | ||
1051 | switch (isar->iis & ISAR_IIS_MSCMSD) { | ||
1052 | case ISAR_IIS_RDATA: | ||
1053 | ch = sel_bch_isar(isar, isar->iis >> 6); | ||
1054 | if (ch) | ||
1055 | isar_rcv_frame(ch); | ||
1056 | else { | ||
1057 | pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", | ||
1058 | isar->name, isar->iis, isar->cmsb, | ||
1059 | isar->clsb); | ||
1060 | isar->write_reg(isar->hw, ISAR_IIA, 0); | ||
1061 | } | ||
1062 | break; | ||
1063 | case ISAR_IIS_GSTEV: | ||
1064 | isar->write_reg(isar->hw, ISAR_IIA, 0); | ||
1065 | isar->bstat |= isar->cmsb; | ||
1066 | check_send(isar, isar->cmsb); | ||
1067 | break; | ||
1068 | case ISAR_IIS_BSTEV: | ||
1069 | #ifdef ERROR_STATISTIC | ||
1070 | ch = sel_bch_isar(isar, isar->iis >> 6); | ||
1071 | if (ch) { | ||
1072 | if (isar->cmsb == BSTEV_TBO) | ||
1073 | ch->bch.err_tx++; | ||
1074 | if (isar->cmsb == BSTEV_RBO) | ||
1075 | ch->bch.err_rdo++; | ||
1076 | } | ||
1077 | #endif | ||
1078 | pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", | ||
1079 | isar->name, isar->iis>>6, isar->cmsb); | ||
1080 | isar->write_reg(isar->hw, ISAR_IIA, 0); | ||
1081 | break; | ||
1082 | case ISAR_IIS_PSTEV: | ||
1083 | ch = sel_bch_isar(isar, isar->iis >> 6); | ||
1084 | if (ch) { | ||
1085 | rcv_mbox(isar, NULL); | ||
1086 | if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) | ||
1087 | isar_pump_statev_modem(ch, isar->cmsb); | ||
1088 | else if (ch->bch.state == ISDN_P_B_T30_FAX) | ||
1089 | isar_pump_statev_fax(ch, isar->cmsb); | ||
1090 | else if (ch->bch.state == ISDN_P_B_RAW) { | ||
1091 | int tt; | ||
1092 | tt = isar->cmsb | 0x30; | ||
1093 | if (tt == 0x3e) | ||
1094 | tt = '*'; | ||
1095 | else if (tt == 0x3f) | ||
1096 | tt = '#'; | ||
1097 | else if (tt > '9') | ||
1098 | tt += 7; | ||
1099 | tt |= DTMF_TONE_VAL; | ||
1100 | _queue_data(&ch->bch.ch, PH_CONTROL_IND, | ||
1101 | MISDN_ID_ANY, sizeof(tt), &tt, | ||
1102 | GFP_ATOMIC); | ||
1103 | } else | ||
1104 | pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", | ||
1105 | isar->name, ch->bch.state, | ||
1106 | isar->cmsb); | ||
1107 | } else { | ||
1108 | pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", | ||
1109 | isar->name, isar->iis, isar->cmsb, | ||
1110 | isar->clsb); | ||
1111 | isar->write_reg(isar->hw, ISAR_IIA, 0); | ||
1112 | } | ||
1113 | break; | ||
1114 | case ISAR_IIS_PSTRSP: | ||
1115 | ch = sel_bch_isar(isar, isar->iis >> 6); | ||
1116 | if (ch) { | ||
1117 | rcv_mbox(isar, NULL); | ||
1118 | isar_pump_status_rsp(ch); | ||
1119 | } else { | ||
1120 | pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", | ||
1121 | isar->name, isar->iis, isar->cmsb, | ||
1122 | isar->clsb); | ||
1123 | isar->write_reg(isar->hw, ISAR_IIA, 0); | ||
1124 | } | ||
1125 | break; | ||
1126 | case ISAR_IIS_DIAG: | ||
1127 | case ISAR_IIS_BSTRSP: | ||
1128 | case ISAR_IIS_IOM2RSP: | ||
1129 | rcv_mbox(isar, NULL); | ||
1130 | break; | ||
1131 | case ISAR_IIS_INVMSG: | ||
1132 | rcv_mbox(isar, NULL); | ||
1133 | pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); | ||
1134 | break; | ||
1135 | default: | ||
1136 | rcv_mbox(isar, NULL); | ||
1137 | pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", | ||
1138 | isar->name, isar->iis, isar->cmsb, isar->clsb); | ||
1139 | break; | ||
1140 | } | ||
1141 | } | ||
1142 | EXPORT_SYMBOL(mISDNisar_irq); | ||
1143 | |||
1144 | static void | ||
1145 | ftimer_handler(unsigned long data) | ||
1146 | { | ||
1147 | struct isar_ch *ch = (struct isar_ch *)data; | ||
1148 | |||
1149 | pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); | ||
1150 | test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); | ||
1151 | if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) | ||
1152 | deliver_status(ch, HW_MOD_CONNECT); | ||
1153 | } | ||
1154 | |||
1155 | static void | ||
1156 | setup_pump(struct isar_ch *ch) { | ||
1157 | u8 dps = SET_DPS(ch->dpath); | ||
1158 | u8 ctrl, param[6]; | ||
1159 | |||
1160 | switch (ch->bch.state) { | ||
1161 | case ISDN_P_NONE: | ||
1162 | case ISDN_P_B_RAW: | ||
1163 | case ISDN_P_B_HDLC: | ||
1164 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); | ||
1165 | break; | ||
1166 | case ISDN_P_B_L2DTMF: | ||
1167 | if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { | ||
1168 | param[0] = 5; /* TOA 5 db */ | ||
1169 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, | ||
1170 | PMOD_DTMF_TRANS, 1, param); | ||
1171 | } else { | ||
1172 | param[0] = 40; /* REL -46 dbm */ | ||
1173 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, | ||
1174 | PMOD_DTMF, 1, param); | ||
1175 | } | ||
1176 | case ISDN_P_B_MODEM_ASYNC: | ||
1177 | ctrl = PMOD_DATAMODEM; | ||
1178 | if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { | ||
1179 | ctrl |= PCTRL_ORIG; | ||
1180 | param[5] = PV32P6_CTN; | ||
1181 | } else { | ||
1182 | param[5] = PV32P6_ATN; | ||
1183 | } | ||
1184 | param[0] = 6; /* 6 db */ | ||
1185 | param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | | ||
1186 | PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; | ||
1187 | param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; | ||
1188 | param[3] = PV32P4_UT144; | ||
1189 | param[4] = PV32P5_UT144; | ||
1190 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); | ||
1191 | break; | ||
1192 | case ISDN_P_B_T30_FAX: | ||
1193 | ctrl = PMOD_FAX; | ||
1194 | if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { | ||
1195 | ctrl |= PCTRL_ORIG; | ||
1196 | param[1] = PFAXP2_CTN; | ||
1197 | } else { | ||
1198 | param[1] = PFAXP2_ATN; | ||
1199 | } | ||
1200 | param[0] = 6; /* 6 db */ | ||
1201 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); | ||
1202 | ch->state = STFAX_NULL; | ||
1203 | ch->newcmd = 0; | ||
1204 | ch->newmod = 0; | ||
1205 | test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); | ||
1206 | break; | ||
1207 | } | ||
1208 | udelay(1000); | ||
1209 | send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); | ||
1210 | udelay(1000); | ||
1211 | } | ||
1212 | |||
1213 | static void | ||
1214 | setup_sart(struct isar_ch *ch) { | ||
1215 | u8 dps = SET_DPS(ch->dpath); | ||
1216 | u8 ctrl, param[2] = {0, 0}; | ||
1217 | |||
1218 | switch (ch->bch.state) { | ||
1219 | case ISDN_P_NONE: | ||
1220 | send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, | ||
1221 | 0, NULL); | ||
1222 | break; | ||
1223 | case ISDN_P_B_RAW: | ||
1224 | case ISDN_P_B_L2DTMF: | ||
1225 | send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, | ||
1226 | 2, param); | ||
1227 | break; | ||
1228 | case ISDN_P_B_HDLC: | ||
1229 | case ISDN_P_B_T30_FAX: | ||
1230 | send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, | ||
1231 | 1, param); | ||
1232 | break; | ||
1233 | case ISDN_P_B_MODEM_ASYNC: | ||
1234 | ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; | ||
1235 | param[0] = S_P1_CHS_8; | ||
1236 | param[1] = S_P2_BFT_DEF; | ||
1237 | send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); | ||
1238 | break; | ||
1239 | } | ||
1240 | udelay(1000); | ||
1241 | send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); | ||
1242 | udelay(1000); | ||
1243 | } | ||
1244 | |||
1245 | static void | ||
1246 | setup_iom2(struct isar_ch *ch) { | ||
1247 | u8 dps = SET_DPS(ch->dpath); | ||
1248 | u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; | ||
1249 | |||
1250 | if (ch->bch.nr == 2) { | ||
1251 | msg[1] = 1; | ||
1252 | msg[3] = 1; | ||
1253 | } | ||
1254 | switch (ch->bch.state) { | ||
1255 | case ISDN_P_NONE: | ||
1256 | cmsb = 0; | ||
1257 | /* dummy slot */ | ||
1258 | msg[1] = ch->dpath + 2; | ||
1259 | msg[3] = ch->dpath + 2; | ||
1260 | break; | ||
1261 | case ISDN_P_B_RAW: | ||
1262 | case ISDN_P_B_HDLC: | ||
1263 | break; | ||
1264 | case ISDN_P_B_MODEM_ASYNC: | ||
1265 | case ISDN_P_B_T30_FAX: | ||
1266 | cmsb |= IOM_CTRL_RCV; | ||
1267 | case ISDN_P_B_L2DTMF: | ||
1268 | if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) | ||
1269 | cmsb |= IOM_CTRL_RCV; | ||
1270 | cmsb |= IOM_CTRL_ALAW; | ||
1271 | break; | ||
1272 | } | ||
1273 | send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); | ||
1274 | udelay(1000); | ||
1275 | send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); | ||
1276 | udelay(1000); | ||
1277 | } | ||
1278 | |||
1279 | static int | ||
1280 | modeisar(struct isar_ch *ch, u32 bprotocol) | ||
1281 | { | ||
1282 | /* Here we are selecting the best datapath for requested protocol */ | ||
1283 | if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ | ||
1284 | switch (bprotocol) { | ||
1285 | case ISDN_P_NONE: /* init */ | ||
1286 | if (!ch->dpath) | ||
1287 | /* no init for dpath 0 */ | ||
1288 | return 0; | ||
1289 | test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); | ||
1290 | test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); | ||
1291 | break; | ||
1292 | case ISDN_P_B_RAW: | ||
1293 | case ISDN_P_B_HDLC: | ||
1294 | /* best is datapath 2 */ | ||
1295 | if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) | ||
1296 | ch->dpath = 2; | ||
1297 | else if (!test_and_set_bit(ISAR_DP1_USE, | ||
1298 | &ch->is->Flags)) | ||
1299 | ch->dpath = 1; | ||
1300 | else { | ||
1301 | pr_info("modeisar both pathes in use\n"); | ||
1302 | return -EBUSY; | ||
1303 | } | ||
1304 | if (bprotocol == ISDN_P_B_HDLC) | ||
1305 | test_and_set_bit(FLG_HDLC, &ch->bch.Flags); | ||
1306 | else | ||
1307 | test_and_set_bit(FLG_TRANSPARENT, | ||
1308 | &ch->bch.Flags); | ||
1309 | break; | ||
1310 | case ISDN_P_B_MODEM_ASYNC: | ||
1311 | case ISDN_P_B_T30_FAX: | ||
1312 | case ISDN_P_B_L2DTMF: | ||
1313 | /* only datapath 1 */ | ||
1314 | if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) | ||
1315 | ch->dpath = 1; | ||
1316 | else { | ||
1317 | pr_info("%s: ISAR modeisar analog functions" | ||
1318 | "only with DP1\n", ch->is->name); | ||
1319 | return -EBUSY; | ||
1320 | } | ||
1321 | break; | ||
1322 | default: | ||
1323 | pr_info("%s: protocol not known %x\n", ch->is->name, | ||
1324 | bprotocol); | ||
1325 | return -ENOPROTOOPT; | ||
1326 | } | ||
1327 | } | ||
1328 | pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, | ||
1329 | ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); | ||
1330 | ch->bch.state = bprotocol; | ||
1331 | setup_pump(ch); | ||
1332 | setup_iom2(ch); | ||
1333 | setup_sart(ch); | ||
1334 | if (ch->bch.state == ISDN_P_NONE) { | ||
1335 | /* Clear resources */ | ||
1336 | if (ch->dpath == 1) | ||
1337 | test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); | ||
1338 | else if (ch->dpath == 2) | ||
1339 | test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); | ||
1340 | ch->dpath = 0; | ||
1341 | ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); | ||
1342 | } else | ||
1343 | ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); | ||
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | static void | ||
1348 | isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) | ||
1349 | { | ||
1350 | u8 dps = SET_DPS(ch->dpath); | ||
1351 | u8 ctrl = 0, nom = 0, p1 = 0; | ||
1352 | |||
1353 | pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", | ||
1354 | ch->is->name, cmd, para, ch->bch.state); | ||
1355 | switch (cmd) { | ||
1356 | case HW_MOD_FTM: | ||
1357 | if (ch->state == STFAX_READY) { | ||
1358 | p1 = para; | ||
1359 | ctrl = PCTRL_CMD_FTM; | ||
1360 | nom = 1; | ||
1361 | ch->state = STFAX_LINE; | ||
1362 | ch->cmd = ctrl; | ||
1363 | ch->mod = para; | ||
1364 | ch->newmod = 0; | ||
1365 | ch->newcmd = 0; | ||
1366 | ch->try_mod = 3; | ||
1367 | } else if ((ch->state == STFAX_ACTIV) && | ||
1368 | (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) | ||
1369 | deliver_status(ch, HW_MOD_CONNECT); | ||
1370 | else { | ||
1371 | ch->newmod = para; | ||
1372 | ch->newcmd = PCTRL_CMD_FTM; | ||
1373 | nom = 0; | ||
1374 | ctrl = PCTRL_CMD_ESC; | ||
1375 | ch->state = STFAX_ESCAPE; | ||
1376 | } | ||
1377 | break; | ||
1378 | case HW_MOD_FTH: | ||
1379 | if (ch->state == STFAX_READY) { | ||
1380 | p1 = para; | ||
1381 | ctrl = PCTRL_CMD_FTH; | ||
1382 | nom = 1; | ||
1383 | ch->state = STFAX_LINE; | ||
1384 | ch->cmd = ctrl; | ||
1385 | ch->mod = para; | ||
1386 | ch->newmod = 0; | ||
1387 | ch->newcmd = 0; | ||
1388 | ch->try_mod = 3; | ||
1389 | } else if ((ch->state == STFAX_ACTIV) && | ||
1390 | (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) | ||
1391 | deliver_status(ch, HW_MOD_CONNECT); | ||
1392 | else { | ||
1393 | ch->newmod = para; | ||
1394 | ch->newcmd = PCTRL_CMD_FTH; | ||
1395 | nom = 0; | ||
1396 | ctrl = PCTRL_CMD_ESC; | ||
1397 | ch->state = STFAX_ESCAPE; | ||
1398 | } | ||
1399 | break; | ||
1400 | case HW_MOD_FRM: | ||
1401 | if (ch->state == STFAX_READY) { | ||
1402 | p1 = para; | ||
1403 | ctrl = PCTRL_CMD_FRM; | ||
1404 | nom = 1; | ||
1405 | ch->state = STFAX_LINE; | ||
1406 | ch->cmd = ctrl; | ||
1407 | ch->mod = para; | ||
1408 | ch->newmod = 0; | ||
1409 | ch->newcmd = 0; | ||
1410 | ch->try_mod = 3; | ||
1411 | } else if ((ch->state == STFAX_ACTIV) && | ||
1412 | (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) | ||
1413 | deliver_status(ch, HW_MOD_CONNECT); | ||
1414 | else { | ||
1415 | ch->newmod = para; | ||
1416 | ch->newcmd = PCTRL_CMD_FRM; | ||
1417 | nom = 0; | ||
1418 | ctrl = PCTRL_CMD_ESC; | ||
1419 | ch->state = STFAX_ESCAPE; | ||
1420 | } | ||
1421 | break; | ||
1422 | case HW_MOD_FRH: | ||
1423 | if (ch->state == STFAX_READY) { | ||
1424 | p1 = para; | ||
1425 | ctrl = PCTRL_CMD_FRH; | ||
1426 | nom = 1; | ||
1427 | ch->state = STFAX_LINE; | ||
1428 | ch->cmd = ctrl; | ||
1429 | ch->mod = para; | ||
1430 | ch->newmod = 0; | ||
1431 | ch->newcmd = 0; | ||
1432 | ch->try_mod = 3; | ||
1433 | } else if ((ch->state == STFAX_ACTIV) && | ||
1434 | (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) | ||
1435 | deliver_status(ch, HW_MOD_CONNECT); | ||
1436 | else { | ||
1437 | ch->newmod = para; | ||
1438 | ch->newcmd = PCTRL_CMD_FRH; | ||
1439 | nom = 0; | ||
1440 | ctrl = PCTRL_CMD_ESC; | ||
1441 | ch->state = STFAX_ESCAPE; | ||
1442 | } | ||
1443 | break; | ||
1444 | case PCTRL_CMD_TDTMF: | ||
1445 | p1 = para; | ||
1446 | nom = 1; | ||
1447 | ctrl = PCTRL_CMD_TDTMF; | ||
1448 | break; | ||
1449 | } | ||
1450 | if (ctrl) | ||
1451 | send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); | ||
1452 | } | ||
1453 | |||
1454 | static void | ||
1455 | isar_setup(struct isar_hw *isar) | ||
1456 | { | ||
1457 | u8 msg; | ||
1458 | int i; | ||
1459 | |||
1460 | /* Dpath 1, 2 */ | ||
1461 | msg = 61; | ||
1462 | for (i = 0; i < 2; i++) { | ||
1463 | /* Buffer Config */ | ||
1464 | send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | | ||
1465 | ISAR_HIS_P12CFG, 4, 1, &msg); | ||
1466 | isar->ch[i].mml = msg; | ||
1467 | isar->ch[i].bch.state = 0; | ||
1468 | isar->ch[i].dpath = i + 1; | ||
1469 | modeisar(&isar->ch[i], ISDN_P_NONE); | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | static int | ||
1474 | isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1475 | { | ||
1476 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1477 | struct isar_ch *ich = container_of(bch, struct isar_ch, bch); | ||
1478 | int ret = -EINVAL; | ||
1479 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1480 | u32 id, *val; | ||
1481 | u_long flags; | ||
1482 | |||
1483 | switch (hh->prim) { | ||
1484 | case PH_DATA_REQ: | ||
1485 | spin_lock_irqsave(ich->is->hwlock, flags); | ||
1486 | ret = bchannel_senddata(bch, skb); | ||
1487 | if (ret > 0) { /* direct TX */ | ||
1488 | id = hh->id; /* skb can be freed */ | ||
1489 | ret = 0; | ||
1490 | isar_fill_fifo(ich); | ||
1491 | spin_unlock_irqrestore(ich->is->hwlock, flags); | ||
1492 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
1493 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
1494 | } else | ||
1495 | spin_unlock_irqrestore(ich->is->hwlock, flags); | ||
1496 | return ret; | ||
1497 | case PH_ACTIVATE_REQ: | ||
1498 | spin_lock_irqsave(ich->is->hwlock, flags); | ||
1499 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
1500 | ret = modeisar(ich, ch->protocol); | ||
1501 | else | ||
1502 | ret = 0; | ||
1503 | spin_unlock_irqrestore(ich->is->hwlock, flags); | ||
1504 | if (!ret) | ||
1505 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
1506 | NULL, GFP_KERNEL); | ||
1507 | break; | ||
1508 | case PH_DEACTIVATE_REQ: | ||
1509 | spin_lock_irqsave(ich->is->hwlock, flags); | ||
1510 | mISDN_clear_bchannel(bch); | ||
1511 | modeisar(ich, ISDN_P_NONE); | ||
1512 | spin_unlock_irqrestore(ich->is->hwlock, flags); | ||
1513 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
1514 | NULL, GFP_KERNEL); | ||
1515 | ret = 0; | ||
1516 | break; | ||
1517 | case PH_CONTROL_REQ: | ||
1518 | val = (u32 *)skb->data; | ||
1519 | pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, | ||
1520 | hh->id, *val); | ||
1521 | if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == | ||
1522 | DTMF_TONE_VAL)) { | ||
1523 | if (bch->state == ISDN_P_B_L2DTMF) { | ||
1524 | char tt = *val & DTMF_TONE_MASK; | ||
1525 | |||
1526 | if (tt == '*') | ||
1527 | tt = 0x1e; | ||
1528 | else if (tt == '#') | ||
1529 | tt = 0x1f; | ||
1530 | else if (tt > '9') | ||
1531 | tt -= 7; | ||
1532 | tt &= 0x1f; | ||
1533 | spin_lock_irqsave(ich->is->hwlock, flags); | ||
1534 | isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); | ||
1535 | spin_unlock_irqrestore(ich->is->hwlock, flags); | ||
1536 | } else { | ||
1537 | pr_info("%s: DTMF send wrong protocol %x\n", | ||
1538 | __func__, bch->state); | ||
1539 | return -EINVAL; | ||
1540 | } | ||
1541 | } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || | ||
1542 | (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { | ||
1543 | for (id = 0; id < FAXMODCNT; id++) | ||
1544 | if (faxmodulation[id] == *val) | ||
1545 | break; | ||
1546 | if ((FAXMODCNT > id) && | ||
1547 | test_bit(FLG_INITIALIZED, &bch->Flags)) { | ||
1548 | pr_debug("%s: isar: new mod\n", ich->is->name); | ||
1549 | isar_pump_cmd(ich, hh->id, *val); | ||
1550 | ret = 0; | ||
1551 | } else { | ||
1552 | pr_info("%s: wrong modulation\n", | ||
1553 | ich->is->name); | ||
1554 | ret = -EINVAL; | ||
1555 | } | ||
1556 | } else if (hh->id == HW_MOD_LASTDATA) | ||
1557 | test_and_set_bit(FLG_DLEETX, &bch->Flags); | ||
1558 | else { | ||
1559 | pr_info("%s: unknown PH_CONTROL_REQ %x\n", | ||
1560 | ich->is->name, hh->id); | ||
1561 | ret = -EINVAL; | ||
1562 | } | ||
1563 | default: | ||
1564 | pr_info("%s: %s unknown prim(%x,%x)\n", | ||
1565 | ich->is->name, __func__, hh->prim, hh->id); | ||
1566 | ret = -EINVAL; | ||
1567 | } | ||
1568 | if (!ret) | ||
1569 | dev_kfree_skb(skb); | ||
1570 | return ret; | ||
1571 | } | ||
1572 | |||
1573 | static int | ||
1574 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
1575 | { | ||
1576 | int ret = 0; | ||
1577 | |||
1578 | switch (cq->op) { | ||
1579 | case MISDN_CTRL_GETOP: | ||
1580 | cq->op = 0; | ||
1581 | break; | ||
1582 | /* Nothing implemented yet */ | ||
1583 | case MISDN_CTRL_FILL_EMPTY: | ||
1584 | default: | ||
1585 | pr_info("%s: unknown Op %x\n", __func__, cq->op); | ||
1586 | ret = -EINVAL; | ||
1587 | break; | ||
1588 | } | ||
1589 | return ret; | ||
1590 | } | ||
1591 | |||
1592 | static int | ||
1593 | isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
1594 | { | ||
1595 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1596 | struct isar_ch *ich = container_of(bch, struct isar_ch, bch); | ||
1597 | int ret = -EINVAL; | ||
1598 | u_long flags; | ||
1599 | |||
1600 | pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); | ||
1601 | switch (cmd) { | ||
1602 | case CLOSE_CHANNEL: | ||
1603 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
1604 | if (test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
1605 | spin_lock_irqsave(ich->is->hwlock, flags); | ||
1606 | mISDN_freebchannel(bch); | ||
1607 | modeisar(ich, ISDN_P_NONE); | ||
1608 | spin_unlock_irqrestore(ich->is->hwlock, flags); | ||
1609 | } else { | ||
1610 | skb_queue_purge(&bch->rqueue); | ||
1611 | bch->rcount = 0; | ||
1612 | } | ||
1613 | ch->protocol = ISDN_P_NONE; | ||
1614 | ch->peer = NULL; | ||
1615 | module_put(ich->is->owner); | ||
1616 | ret = 0; | ||
1617 | break; | ||
1618 | case CONTROL_CHANNEL: | ||
1619 | ret = channel_bctrl(bch, arg); | ||
1620 | break; | ||
1621 | default: | ||
1622 | pr_info("%s: %s unknown prim(%x)\n", | ||
1623 | ich->is->name, __func__, cmd); | ||
1624 | } | ||
1625 | return ret; | ||
1626 | } | ||
1627 | |||
1628 | static void | ||
1629 | free_isar(struct isar_hw *isar) | ||
1630 | { | ||
1631 | modeisar(&isar->ch[0], ISDN_P_NONE); | ||
1632 | modeisar(&isar->ch[1], ISDN_P_NONE); | ||
1633 | del_timer(&isar->ch[0].ftimer); | ||
1634 | del_timer(&isar->ch[1].ftimer); | ||
1635 | test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); | ||
1636 | test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); | ||
1637 | } | ||
1638 | |||
1639 | static int | ||
1640 | init_isar(struct isar_hw *isar) | ||
1641 | { | ||
1642 | int cnt = 3; | ||
1643 | |||
1644 | while (cnt--) { | ||
1645 | isar->version = ISARVersion(isar); | ||
1646 | if (isar->ch[0].bch.debug & DEBUG_HW) | ||
1647 | pr_notice("%s: Testing version %d (%d time)\n", | ||
1648 | isar->name, isar->version, 3 - cnt); | ||
1649 | if (isar->version == 1) | ||
1650 | break; | ||
1651 | isar->ctrl(isar->hw, HW_RESET_REQ, 0); | ||
1652 | } | ||
1653 | if (isar->version != 1) | ||
1654 | return -EINVAL; | ||
1655 | isar->ch[0].ftimer.function = &ftimer_handler; | ||
1656 | isar->ch[0].ftimer.data = (long)&isar->ch[0]; | ||
1657 | init_timer(&isar->ch[0].ftimer); | ||
1658 | test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); | ||
1659 | isar->ch[1].ftimer.function = &ftimer_handler; | ||
1660 | isar->ch[1].ftimer.data = (long)&isar->ch[1]; | ||
1661 | init_timer(&isar->ch[1].ftimer); | ||
1662 | test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | static int | ||
1667 | isar_open(struct isar_hw *isar, struct channel_req *rq) | ||
1668 | { | ||
1669 | struct bchannel *bch; | ||
1670 | |||
1671 | if (rq->adr.channel > 2) | ||
1672 | return -EINVAL; | ||
1673 | if (rq->protocol == ISDN_P_NONE) | ||
1674 | return -EINVAL; | ||
1675 | bch = &isar->ch[rq->adr.channel - 1].bch; | ||
1676 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
1677 | return -EBUSY; /* b-channel can be only open once */ | ||
1678 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | ||
1679 | bch->ch.protocol = rq->protocol; | ||
1680 | rq->ch = &bch->ch; | ||
1681 | return 0; | ||
1682 | } | ||
1683 | |||
1684 | u32 | ||
1685 | mISDNisar_init(struct isar_hw *isar, void *hw) | ||
1686 | { | ||
1687 | u32 ret, i; | ||
1688 | |||
1689 | isar->hw = hw; | ||
1690 | for (i = 0; i < 2; i++) { | ||
1691 | isar->ch[i].bch.nr = i + 1; | ||
1692 | mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM); | ||
1693 | isar->ch[i].bch.ch.nr = i + 1; | ||
1694 | isar->ch[i].bch.ch.send = &isar_l2l1; | ||
1695 | isar->ch[i].bch.ch.ctrl = isar_bctrl; | ||
1696 | isar->ch[i].bch.hw = hw; | ||
1697 | isar->ch[i].is = isar; | ||
1698 | } | ||
1699 | |||
1700 | isar->init = &init_isar; | ||
1701 | isar->release = &free_isar; | ||
1702 | isar->firmware = &load_firmware; | ||
1703 | isar->open = &isar_open; | ||
1704 | |||
1705 | ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1706 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | | ||
1707 | (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | | ||
1708 | (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | | ||
1709 | (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); | ||
1710 | |||
1711 | return ret; | ||
1712 | } | ||
1713 | EXPORT_SYMBOL(mISDNisar_init); | ||
1714 | |||
1715 | static int isar_mod_init(void) | ||
1716 | { | ||
1717 | pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); | ||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1721 | static void isar_mod_cleanup(void) | ||
1722 | { | ||
1723 | pr_notice("mISDN: ISAR module unloaded\n"); | ||
1724 | } | ||
1725 | module_init(isar_mod_init); | ||
1726 | module_exit(isar_mod_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c new file mode 100644 index 000000000000..6c1b164937a9 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/netjet.c | |||
@@ -0,0 +1,1156 @@ | |||
1 | /* | ||
2 | * NETJet mISDN driver | ||
3 | * | ||
4 | * Author Karsten Keil <keil@isdn4linux.de> | ||
5 | * | ||
6 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/mISDNhw.h> | ||
27 | #include "ipac.h" | ||
28 | #include "iohelper.h" | ||
29 | #include "netjet.h" | ||
30 | #include <linux/isdn/hdlc.h> | ||
31 | |||
32 | #define NETJET_REV "2.0" | ||
33 | |||
34 | enum nj_types { | ||
35 | NETJET_S_TJ300, | ||
36 | NETJET_S_TJ320, | ||
37 | ENTERNOW__TJ320, | ||
38 | }; | ||
39 | |||
40 | struct tiger_dma { | ||
41 | size_t size; | ||
42 | u32 *start; | ||
43 | int idx; | ||
44 | u32 dmastart; | ||
45 | u32 dmairq; | ||
46 | u32 dmaend; | ||
47 | u32 dmacur; | ||
48 | }; | ||
49 | |||
50 | struct tiger_hw; | ||
51 | |||
52 | struct tiger_ch { | ||
53 | struct bchannel bch; | ||
54 | struct tiger_hw *nj; | ||
55 | int idx; | ||
56 | int free; | ||
57 | int lastrx; | ||
58 | u16 rxstate; | ||
59 | u16 txstate; | ||
60 | struct isdnhdlc_vars hsend; | ||
61 | struct isdnhdlc_vars hrecv; | ||
62 | u8 *hsbuf; | ||
63 | u8 *hrbuf; | ||
64 | }; | ||
65 | |||
66 | #define TX_INIT 0x0001 | ||
67 | #define TX_IDLE 0x0002 | ||
68 | #define TX_RUN 0x0004 | ||
69 | #define TX_UNDERRUN 0x0100 | ||
70 | #define RX_OVERRUN 0x0100 | ||
71 | |||
72 | #define LOG_SIZE 64 | ||
73 | |||
74 | struct tiger_hw { | ||
75 | struct list_head list; | ||
76 | struct pci_dev *pdev; | ||
77 | char name[MISDN_MAX_IDLEN]; | ||
78 | enum nj_types typ; | ||
79 | int irq; | ||
80 | u32 irqcnt; | ||
81 | u32 base; | ||
82 | size_t base_s; | ||
83 | dma_addr_t dma; | ||
84 | void *dma_p; | ||
85 | spinlock_t lock; /* lock HW */ | ||
86 | struct isac_hw isac; | ||
87 | struct tiger_dma send; | ||
88 | struct tiger_dma recv; | ||
89 | struct tiger_ch bc[2]; | ||
90 | u8 ctrlreg; | ||
91 | u8 dmactrl; | ||
92 | u8 auxd; | ||
93 | u8 last_is0; | ||
94 | u8 irqmask0; | ||
95 | char log[LOG_SIZE]; | ||
96 | }; | ||
97 | |||
98 | static LIST_HEAD(Cards); | ||
99 | static DEFINE_RWLOCK(card_lock); /* protect Cards */ | ||
100 | static u32 debug; | ||
101 | static int nj_cnt; | ||
102 | |||
103 | static void | ||
104 | _set_debug(struct tiger_hw *card) | ||
105 | { | ||
106 | card->isac.dch.debug = debug; | ||
107 | card->bc[0].bch.debug = debug; | ||
108 | card->bc[1].bch.debug = debug; | ||
109 | } | ||
110 | |||
111 | static int | ||
112 | set_debug(const char *val, struct kernel_param *kp) | ||
113 | { | ||
114 | int ret; | ||
115 | struct tiger_hw *card; | ||
116 | |||
117 | ret = param_set_uint(val, kp); | ||
118 | if (!ret) { | ||
119 | read_lock(&card_lock); | ||
120 | list_for_each_entry(card, &Cards, list) | ||
121 | _set_debug(card); | ||
122 | read_unlock(&card_lock); | ||
123 | } | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | MODULE_AUTHOR("Karsten Keil"); | ||
128 | MODULE_LICENSE("GPL v2"); | ||
129 | MODULE_VERSION(NETJET_REV); | ||
130 | module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); | ||
131 | MODULE_PARM_DESC(debug, "Netjet debug mask"); | ||
132 | |||
133 | static void | ||
134 | nj_disable_hwirq(struct tiger_hw *card) | ||
135 | { | ||
136 | outb(0, card->base + NJ_IRQMASK0); | ||
137 | outb(0, card->base + NJ_IRQMASK1); | ||
138 | } | ||
139 | |||
140 | |||
141 | static u8 | ||
142 | ReadISAC_nj(void *p, u8 offset) | ||
143 | { | ||
144 | struct tiger_hw *card = p; | ||
145 | u8 ret; | ||
146 | |||
147 | card->auxd &= 0xfc; | ||
148 | card->auxd |= (offset >> 4) & 3; | ||
149 | outb(card->auxd, card->base + NJ_AUXDATA); | ||
150 | ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static void | ||
155 | WriteISAC_nj(void *p, u8 offset, u8 value) | ||
156 | { | ||
157 | struct tiger_hw *card = p; | ||
158 | |||
159 | card->auxd &= 0xfc; | ||
160 | card->auxd |= (offset >> 4) & 3; | ||
161 | outb(card->auxd, card->base + NJ_AUXDATA); | ||
162 | outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); | ||
163 | } | ||
164 | |||
165 | static void | ||
166 | ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) | ||
167 | { | ||
168 | struct tiger_hw *card = p; | ||
169 | |||
170 | card->auxd &= 0xfc; | ||
171 | outb(card->auxd, card->base + NJ_AUXDATA); | ||
172 | insb(card->base + NJ_ISAC_OFF, data, size); | ||
173 | } | ||
174 | |||
175 | static void | ||
176 | WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) | ||
177 | { | ||
178 | struct tiger_hw *card = p; | ||
179 | |||
180 | card->auxd &= 0xfc; | ||
181 | outb(card->auxd, card->base + NJ_AUXDATA); | ||
182 | outsb(card->base + NJ_ISAC_OFF, data, size); | ||
183 | } | ||
184 | |||
185 | static void | ||
186 | fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill) | ||
187 | { | ||
188 | struct tiger_hw *card = bc->bch.hw; | ||
189 | u32 mask = 0xff, val; | ||
190 | |||
191 | pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name, | ||
192 | bc->bch.nr, fill, cnt, idx, card->send.idx); | ||
193 | if (bc->bch.nr & 2) { | ||
194 | fill <<= 8; | ||
195 | mask <<= 8; | ||
196 | } | ||
197 | mask ^= 0xffffffff; | ||
198 | while (cnt--) { | ||
199 | val = card->send.start[idx]; | ||
200 | val &= mask; | ||
201 | val |= fill; | ||
202 | card->send.start[idx++] = val; | ||
203 | if (idx >= card->send.size) | ||
204 | idx = 0; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static int | ||
209 | mode_tiger(struct tiger_ch *bc, u32 protocol) | ||
210 | { | ||
211 | struct tiger_hw *card = bc->bch.hw; | ||
212 | |||
213 | pr_debug("%s: B%1d protocol %x-->%x\n", card->name, | ||
214 | bc->bch.nr, bc->bch.state, protocol); | ||
215 | switch (protocol) { | ||
216 | case ISDN_P_NONE: | ||
217 | if (bc->bch.state == ISDN_P_NONE) | ||
218 | break; | ||
219 | fill_mem(bc, 0, card->send.size, 0xff); | ||
220 | bc->bch.state = protocol; | ||
221 | /* only stop dma and interrupts if both channels NULL */ | ||
222 | if ((card->bc[0].bch.state == ISDN_P_NONE) && | ||
223 | (card->bc[1].bch.state == ISDN_P_NONE)) { | ||
224 | card->dmactrl = 0; | ||
225 | outb(card->dmactrl, card->base + NJ_DMACTRL); | ||
226 | outb(0, card->base + NJ_IRQMASK0); | ||
227 | } | ||
228 | test_and_clear_bit(FLG_HDLC, &bc->bch.Flags); | ||
229 | test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags); | ||
230 | bc->txstate = 0; | ||
231 | bc->rxstate = 0; | ||
232 | bc->lastrx = -1; | ||
233 | break; | ||
234 | case ISDN_P_B_RAW: | ||
235 | test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags); | ||
236 | bc->bch.state = protocol; | ||
237 | bc->idx = 0; | ||
238 | bc->free = card->send.size/2; | ||
239 | bc->rxstate = 0; | ||
240 | bc->txstate = TX_INIT | TX_IDLE; | ||
241 | bc->lastrx = -1; | ||
242 | if (!card->dmactrl) { | ||
243 | card->dmactrl = 1; | ||
244 | outb(card->dmactrl, card->base + NJ_DMACTRL); | ||
245 | outb(0x0f, card->base + NJ_IRQMASK0); | ||
246 | } | ||
247 | break; | ||
248 | case ISDN_P_B_HDLC: | ||
249 | test_and_set_bit(FLG_HDLC, &bc->bch.Flags); | ||
250 | bc->bch.state = protocol; | ||
251 | bc->idx = 0; | ||
252 | bc->free = card->send.size/2; | ||
253 | bc->rxstate = 0; | ||
254 | bc->txstate = TX_INIT | TX_IDLE; | ||
255 | isdnhdlc_rcv_init(&bc->hrecv, 0); | ||
256 | isdnhdlc_out_init(&bc->hsend, 0); | ||
257 | bc->lastrx = -1; | ||
258 | if (!card->dmactrl) { | ||
259 | card->dmactrl = 1; | ||
260 | outb(card->dmactrl, card->base + NJ_DMACTRL); | ||
261 | outb(0x0f, card->base + NJ_IRQMASK0); | ||
262 | } | ||
263 | break; | ||
264 | default: | ||
265 | pr_info("%s: %s protocol %x not handled\n", card->name, | ||
266 | __func__, protocol); | ||
267 | return -ENOPROTOOPT; | ||
268 | } | ||
269 | card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR); | ||
270 | card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR); | ||
271 | card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; | ||
272 | card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; | ||
273 | pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n", | ||
274 | card->name, __func__, | ||
275 | inb(card->base + NJ_DMACTRL), | ||
276 | inb(card->base + NJ_IRQMASK0), | ||
277 | inb(card->base + NJ_IRQSTAT0), | ||
278 | card->send.idx, | ||
279 | card->recv.idx); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static void | ||
284 | nj_reset(struct tiger_hw *card) | ||
285 | { | ||
286 | outb(0xff, card->base + NJ_CTRL); /* Reset On */ | ||
287 | mdelay(1); | ||
288 | |||
289 | /* now edge triggered for TJ320 GE 13/07/00 */ | ||
290 | /* see comment in IRQ function */ | ||
291 | if (card->typ == NETJET_S_TJ320) /* TJ320 */ | ||
292 | card->ctrlreg = 0x40; /* Reset Off and status read clear */ | ||
293 | else | ||
294 | card->ctrlreg = 0x00; /* Reset Off and status read clear */ | ||
295 | outb(card->ctrlreg, card->base + NJ_CTRL); | ||
296 | mdelay(10); | ||
297 | |||
298 | /* configure AUX pins (all output except ISAC IRQ pin) */ | ||
299 | card->auxd = 0; | ||
300 | card->dmactrl = 0; | ||
301 | outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL); | ||
302 | outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1); | ||
303 | outb(card->auxd, card->base + NJ_AUXDATA); | ||
304 | } | ||
305 | |||
306 | static int | ||
307 | inittiger(struct tiger_hw *card) | ||
308 | { | ||
309 | int i; | ||
310 | |||
311 | card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE, | ||
312 | &card->dma); | ||
313 | if (!card->dma_p) { | ||
314 | pr_info("%s: No DMA memory\n", card->name); | ||
315 | return -ENOMEM; | ||
316 | } | ||
317 | if ((u64)card->dma > 0xffffffff) { | ||
318 | pr_info("%s: DMA outside 32 bit\n", card->name); | ||
319 | return -ENOMEM; | ||
320 | } | ||
321 | for (i = 0; i < 2; i++) { | ||
322 | card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL); | ||
323 | if (!card->bc[i].hsbuf) { | ||
324 | pr_info("%s: no B%d send buffer\n", card->name, i + 1); | ||
325 | return -ENOMEM; | ||
326 | } | ||
327 | card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL); | ||
328 | if (!card->bc[i].hrbuf) { | ||
329 | pr_info("%s: no B%d recv buffer\n", card->name, i + 1); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | } | ||
333 | memset(card->dma_p, 0xff, NJ_DMA_SIZE); | ||
334 | |||
335 | card->send.start = card->dma_p; | ||
336 | card->send.dmastart = (u32)card->dma; | ||
337 | card->send.dmaend = card->send.dmastart + | ||
338 | (4 * (NJ_DMA_TXSIZE - 1)); | ||
339 | card->send.dmairq = card->send.dmastart + | ||
340 | (4 * ((NJ_DMA_TXSIZE / 2) - 1)); | ||
341 | card->send.size = NJ_DMA_TXSIZE; | ||
342 | |||
343 | if (debug & DEBUG_HW) | ||
344 | pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p" | ||
345 | " size %zu u32\n", card->name, | ||
346 | card->send.dmastart, card->send.dmairq, | ||
347 | card->send.dmaend, card->send.start, card->send.size); | ||
348 | |||
349 | outl(card->send.dmastart, card->base + NJ_DMA_READ_START); | ||
350 | outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ); | ||
351 | outl(card->send.dmaend, card->base + NJ_DMA_READ_END); | ||
352 | |||
353 | card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2); | ||
354 | card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2); | ||
355 | card->recv.dmaend = card->recv.dmastart + | ||
356 | (4 * (NJ_DMA_RXSIZE - 1)); | ||
357 | card->recv.dmairq = card->recv.dmastart + | ||
358 | (4 * ((NJ_DMA_RXSIZE / 2) - 1)); | ||
359 | card->recv.size = NJ_DMA_RXSIZE; | ||
360 | |||
361 | if (debug & DEBUG_HW) | ||
362 | pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p" | ||
363 | " size %zu u32\n", card->name, | ||
364 | card->recv.dmastart, card->recv.dmairq, | ||
365 | card->recv.dmaend, card->recv.start, card->recv.size); | ||
366 | |||
367 | outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START); | ||
368 | outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ); | ||
369 | outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END); | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static void | ||
374 | read_dma(struct tiger_ch *bc, u32 idx, int cnt) | ||
375 | { | ||
376 | struct tiger_hw *card = bc->bch.hw; | ||
377 | int i, stat; | ||
378 | u32 val; | ||
379 | u8 *p, *pn; | ||
380 | |||
381 | if (bc->lastrx == idx) { | ||
382 | bc->rxstate |= RX_OVERRUN; | ||
383 | pr_info("%s: B%1d overrun at idx %d\n", card->name, | ||
384 | bc->bch.nr, idx); | ||
385 | } | ||
386 | bc->lastrx = idx; | ||
387 | if (!bc->bch.rx_skb) { | ||
388 | bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC); | ||
389 | if (!bc->bch.rx_skb) { | ||
390 | pr_info("%s: B%1d receive out of memory\n", | ||
391 | card->name, bc->bch.nr); | ||
392 | return; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { | ||
397 | if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) { | ||
398 | pr_debug("%s: B%1d overrun %d\n", card->name, | ||
399 | bc->bch.nr, bc->bch.rx_skb->len + cnt); | ||
400 | skb_trim(bc->bch.rx_skb, 0); | ||
401 | return; | ||
402 | } | ||
403 | p = skb_put(bc->bch.rx_skb, cnt); | ||
404 | } else | ||
405 | p = bc->hrbuf; | ||
406 | |||
407 | for (i = 0; i < cnt; i++) { | ||
408 | val = card->recv.start[idx++]; | ||
409 | if (bc->bch.nr & 2) | ||
410 | val >>= 8; | ||
411 | if (idx >= card->recv.size) | ||
412 | idx = 0; | ||
413 | p[i] = val & 0xff; | ||
414 | } | ||
415 | pn = bc->hrbuf; | ||
416 | next_frame: | ||
417 | if (test_bit(FLG_HDLC, &bc->bch.Flags)) { | ||
418 | stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, | ||
419 | bc->bch.rx_skb->data, bc->bch.maxlen); | ||
420 | if (stat > 0) /* valid frame received */ | ||
421 | p = skb_put(bc->bch.rx_skb, stat); | ||
422 | else if (stat == -HDLC_CRC_ERROR) | ||
423 | pr_info("%s: B%1d receive frame CRC error\n", | ||
424 | card->name, bc->bch.nr); | ||
425 | else if (stat == -HDLC_FRAMING_ERROR) | ||
426 | pr_info("%s: B%1d receive framing error\n", | ||
427 | card->name, bc->bch.nr); | ||
428 | else if (stat == -HDLC_LENGTH_ERROR) | ||
429 | pr_info("%s: B%1d receive frame too long (> %d)\n", | ||
430 | card->name, bc->bch.nr, bc->bch.maxlen); | ||
431 | } else | ||
432 | stat = cnt; | ||
433 | |||
434 | if (stat > 0) { | ||
435 | if (debug & DEBUG_HW_BFIFO) { | ||
436 | snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ", | ||
437 | bc->bch.nr, card->name, stat); | ||
438 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, | ||
439 | p, stat); | ||
440 | } | ||
441 | recv_Bchannel(&bc->bch, 0); | ||
442 | } | ||
443 | if (test_bit(FLG_HDLC, &bc->bch.Flags)) { | ||
444 | pn += i; | ||
445 | cnt -= i; | ||
446 | if (!bc->bch.rx_skb) { | ||
447 | bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, | ||
448 | GFP_ATOMIC); | ||
449 | if (!bc->bch.rx_skb) { | ||
450 | pr_info("%s: B%1d receive out of memory\n", | ||
451 | card->name, bc->bch.nr); | ||
452 | return; | ||
453 | } | ||
454 | } | ||
455 | if (cnt > 0) | ||
456 | goto next_frame; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static void | ||
461 | recv_tiger(struct tiger_hw *card, u8 irq_stat) | ||
462 | { | ||
463 | u32 idx; | ||
464 | int cnt = card->recv.size / 2; | ||
465 | |||
466 | /* Note receive is via the WRITE DMA channel */ | ||
467 | card->last_is0 &= ~NJ_IRQM0_WR_MASK; | ||
468 | card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK); | ||
469 | |||
470 | if (irq_stat & NJ_IRQM0_WR_END) | ||
471 | idx = cnt - 1; | ||
472 | else | ||
473 | idx = card->recv.size - 1; | ||
474 | |||
475 | if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags)) | ||
476 | read_dma(&card->bc[0], idx, cnt); | ||
477 | if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags)) | ||
478 | read_dma(&card->bc[1], idx, cnt); | ||
479 | } | ||
480 | |||
481 | /* sync with current DMA address at start or after exception */ | ||
482 | static void | ||
483 | resync(struct tiger_ch *bc, struct tiger_hw *card) | ||
484 | { | ||
485 | card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); | ||
486 | card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; | ||
487 | if (bc->free > card->send.size / 2) | ||
488 | bc->free = card->send.size / 2; | ||
489 | /* currently we simple sync to the next complete free area | ||
490 | * this hast the advantage that we have always maximum time to | ||
491 | * handle TX irq | ||
492 | */ | ||
493 | if (card->send.idx < ((card->send.size / 2) - 1)) | ||
494 | bc->idx = (card->recv.size / 2) - 1; | ||
495 | else | ||
496 | bc->idx = card->recv.size - 1; | ||
497 | bc->txstate = TX_RUN; | ||
498 | pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name, | ||
499 | __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx); | ||
500 | } | ||
501 | |||
502 | static int bc_next_frame(struct tiger_ch *); | ||
503 | |||
504 | static void | ||
505 | fill_hdlc_flag(struct tiger_ch *bc) | ||
506 | { | ||
507 | struct tiger_hw *card = bc->bch.hw; | ||
508 | int count, i; | ||
509 | u32 m, v; | ||
510 | u8 *p; | ||
511 | |||
512 | if (bc->free == 0) | ||
513 | return; | ||
514 | pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name, | ||
515 | __func__, bc->bch.nr, bc->free, bc->txstate, | ||
516 | bc->idx, card->send.idx); | ||
517 | if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) | ||
518 | resync(bc, card); | ||
519 | count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i, | ||
520 | bc->hsbuf, bc->free); | ||
521 | pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name, | ||
522 | bc->bch.nr, count); | ||
523 | bc->free -= count; | ||
524 | p = bc->hsbuf; | ||
525 | m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; | ||
526 | for (i = 0; i < count; i++) { | ||
527 | if (bc->idx >= card->send.size) | ||
528 | bc->idx = 0; | ||
529 | v = card->send.start[bc->idx]; | ||
530 | v &= m; | ||
531 | v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; | ||
532 | card->send.start[bc->idx++] = v; | ||
533 | } | ||
534 | if (debug & DEBUG_HW_BFIFO) { | ||
535 | snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", | ||
536 | bc->bch.nr, card->name, count); | ||
537 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | static void | ||
542 | fill_dma(struct tiger_ch *bc) | ||
543 | { | ||
544 | struct tiger_hw *card = bc->bch.hw; | ||
545 | int count, i; | ||
546 | u32 m, v; | ||
547 | u8 *p; | ||
548 | |||
549 | if (bc->free == 0) | ||
550 | return; | ||
551 | count = bc->bch.tx_skb->len - bc->bch.tx_idx; | ||
552 | if (count <= 0) | ||
553 | return; | ||
554 | pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name, | ||
555 | __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx, | ||
556 | bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx); | ||
557 | if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) | ||
558 | resync(bc, card); | ||
559 | p = bc->bch.tx_skb->data + bc->bch.tx_idx; | ||
560 | if (test_bit(FLG_HDLC, &bc->bch.Flags)) { | ||
561 | count = isdnhdlc_encode(&bc->hsend, p, count, &i, | ||
562 | bc->hsbuf, bc->free); | ||
563 | pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name, | ||
564 | bc->bch.nr, i, count); | ||
565 | bc->bch.tx_idx += i; | ||
566 | bc->free -= count; | ||
567 | p = bc->hsbuf; | ||
568 | } else { | ||
569 | if (count > bc->free) | ||
570 | count = bc->free; | ||
571 | bc->bch.tx_idx += count; | ||
572 | bc->free -= count; | ||
573 | } | ||
574 | m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; | ||
575 | for (i = 0; i < count; i++) { | ||
576 | if (bc->idx >= card->send.size) | ||
577 | bc->idx = 0; | ||
578 | v = card->send.start[bc->idx]; | ||
579 | v &= m; | ||
580 | v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; | ||
581 | card->send.start[bc->idx++] = v; | ||
582 | } | ||
583 | if (debug & DEBUG_HW_BFIFO) { | ||
584 | snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", | ||
585 | bc->bch.nr, card->name, count); | ||
586 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); | ||
587 | } | ||
588 | if (bc->free) | ||
589 | bc_next_frame(bc); | ||
590 | } | ||
591 | |||
592 | |||
593 | static int | ||
594 | bc_next_frame(struct tiger_ch *bc) | ||
595 | { | ||
596 | if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) | ||
597 | fill_dma(bc); | ||
598 | else { | ||
599 | if (bc->bch.tx_skb) { | ||
600 | /* send confirm, on trans, free on hdlc. */ | ||
601 | if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) | ||
602 | confirm_Bsend(&bc->bch); | ||
603 | dev_kfree_skb(bc->bch.tx_skb); | ||
604 | } | ||
605 | if (get_next_bframe(&bc->bch)) | ||
606 | fill_dma(bc); | ||
607 | else | ||
608 | return 0; | ||
609 | } | ||
610 | return 1; | ||
611 | } | ||
612 | |||
613 | static void | ||
614 | send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc) | ||
615 | { | ||
616 | int ret; | ||
617 | |||
618 | bc->free += card->send.size / 2; | ||
619 | if (bc->free >= card->send.size) { | ||
620 | if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) { | ||
621 | pr_info("%s: B%1d TX underrun state %x\n", card->name, | ||
622 | bc->bch.nr, bc->txstate); | ||
623 | bc->txstate |= TX_UNDERRUN; | ||
624 | } | ||
625 | bc->free = card->send.size; | ||
626 | } | ||
627 | ret = bc_next_frame(bc); | ||
628 | if (!ret) { | ||
629 | if (test_bit(FLG_HDLC, &bc->bch.Flags)) { | ||
630 | fill_hdlc_flag(bc); | ||
631 | return; | ||
632 | } | ||
633 | pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name, | ||
634 | bc->bch.nr, bc->free, bc->idx, card->send.idx); | ||
635 | if (!(bc->txstate & (TX_IDLE | TX_INIT))) { | ||
636 | fill_mem(bc, bc->idx, bc->free, 0xff); | ||
637 | if (bc->free == card->send.size) | ||
638 | bc->txstate |= TX_IDLE; | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | |||
643 | static void | ||
644 | send_tiger(struct tiger_hw *card, u8 irq_stat) | ||
645 | { | ||
646 | int i; | ||
647 | |||
648 | /* Note send is via the READ DMA channel */ | ||
649 | if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) { | ||
650 | pr_info("%s: tiger warn write double dma %x/%x\n", | ||
651 | card->name, irq_stat, card->last_is0); | ||
652 | return; | ||
653 | } else { | ||
654 | card->last_is0 &= ~NJ_IRQM0_RD_MASK; | ||
655 | card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK); | ||
656 | } | ||
657 | for (i = 0; i < 2; i++) { | ||
658 | if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags)) | ||
659 | send_tiger_bc(card, &card->bc[i]); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static irqreturn_t | ||
664 | nj_irq(int intno, void *dev_id) | ||
665 | { | ||
666 | struct tiger_hw *card = dev_id; | ||
667 | u8 val, s1val, s0val; | ||
668 | |||
669 | spin_lock(&card->lock); | ||
670 | s0val = inb(card->base | NJ_IRQSTAT0); | ||
671 | s1val = inb(card->base | NJ_IRQSTAT1); | ||
672 | if ((s1val & NJ_ISACIRQ) && (s0val == 0)) { | ||
673 | /* shared IRQ */ | ||
674 | spin_unlock(&card->lock); | ||
675 | return IRQ_NONE; | ||
676 | } | ||
677 | pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val); | ||
678 | card->irqcnt++; | ||
679 | if (!(s1val & NJ_ISACIRQ)) { | ||
680 | val = ReadISAC_nj(card, ISAC_ISTA); | ||
681 | if (val) | ||
682 | mISDNisac_irq(&card->isac, val); | ||
683 | } | ||
684 | |||
685 | if (s0val) | ||
686 | /* write to clear */ | ||
687 | outb(s0val, card->base | NJ_IRQSTAT0); | ||
688 | else | ||
689 | goto end; | ||
690 | s1val = s0val; | ||
691 | /* set bits in sval to indicate which page is free */ | ||
692 | card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR); | ||
693 | card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; | ||
694 | if (card->recv.dmacur < card->recv.dmairq) | ||
695 | s0val = 0x08; /* the 2nd write area is free */ | ||
696 | else | ||
697 | s0val = 0x04; /* the 1st write area is free */ | ||
698 | |||
699 | card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); | ||
700 | card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; | ||
701 | if (card->send.dmacur < card->send.dmairq) | ||
702 | s0val |= 0x02; /* the 2nd read area is free */ | ||
703 | else | ||
704 | s0val |= 0x01; /* the 1st read area is free */ | ||
705 | |||
706 | pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name, | ||
707 | s1val, s0val, card->last_is0, | ||
708 | card->recv.idx, card->send.idx); | ||
709 | /* test if we have a DMA interrupt */ | ||
710 | if (s0val != card->last_is0) { | ||
711 | if ((s0val & NJ_IRQM0_RD_MASK) != | ||
712 | (card->last_is0 & NJ_IRQM0_RD_MASK)) | ||
713 | /* got a write dma int */ | ||
714 | send_tiger(card, s0val); | ||
715 | if ((s0val & NJ_IRQM0_WR_MASK) != | ||
716 | (card->last_is0 & NJ_IRQM0_WR_MASK)) | ||
717 | /* got a read dma int */ | ||
718 | recv_tiger(card, s0val); | ||
719 | } | ||
720 | end: | ||
721 | spin_unlock(&card->lock); | ||
722 | return IRQ_HANDLED; | ||
723 | } | ||
724 | |||
725 | static int | ||
726 | nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) | ||
727 | { | ||
728 | int ret = -EINVAL; | ||
729 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
730 | struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); | ||
731 | struct tiger_hw *card = bch->hw; | ||
732 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
733 | u32 id; | ||
734 | u_long flags; | ||
735 | |||
736 | switch (hh->prim) { | ||
737 | case PH_DATA_REQ: | ||
738 | spin_lock_irqsave(&card->lock, flags); | ||
739 | ret = bchannel_senddata(bch, skb); | ||
740 | if (ret > 0) { /* direct TX */ | ||
741 | id = hh->id; /* skb can be freed */ | ||
742 | fill_dma(bc); | ||
743 | ret = 0; | ||
744 | spin_unlock_irqrestore(&card->lock, flags); | ||
745 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
746 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
747 | } else | ||
748 | spin_unlock_irqrestore(&card->lock, flags); | ||
749 | return ret; | ||
750 | case PH_ACTIVATE_REQ: | ||
751 | spin_lock_irqsave(&card->lock, flags); | ||
752 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
753 | ret = mode_tiger(bc, ch->protocol); | ||
754 | else | ||
755 | ret = 0; | ||
756 | spin_unlock_irqrestore(&card->lock, flags); | ||
757 | if (!ret) | ||
758 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
759 | NULL, GFP_KERNEL); | ||
760 | break; | ||
761 | case PH_DEACTIVATE_REQ: | ||
762 | spin_lock_irqsave(&card->lock, flags); | ||
763 | mISDN_clear_bchannel(bch); | ||
764 | mode_tiger(bc, ISDN_P_NONE); | ||
765 | spin_unlock_irqrestore(&card->lock, flags); | ||
766 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
767 | NULL, GFP_KERNEL); | ||
768 | ret = 0; | ||
769 | break; | ||
770 | } | ||
771 | if (!ret) | ||
772 | dev_kfree_skb(skb); | ||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | static int | ||
777 | channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq) | ||
778 | { | ||
779 | int ret = 0; | ||
780 | struct tiger_hw *card = bc->bch.hw; | ||
781 | |||
782 | switch (cq->op) { | ||
783 | case MISDN_CTRL_GETOP: | ||
784 | cq->op = 0; | ||
785 | break; | ||
786 | /* Nothing implemented yet */ | ||
787 | case MISDN_CTRL_FILL_EMPTY: | ||
788 | default: | ||
789 | pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); | ||
790 | ret = -EINVAL; | ||
791 | break; | ||
792 | } | ||
793 | return ret; | ||
794 | } | ||
795 | |||
796 | static int | ||
797 | nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
798 | { | ||
799 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
800 | struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); | ||
801 | struct tiger_hw *card = bch->hw; | ||
802 | int ret = -EINVAL; | ||
803 | u_long flags; | ||
804 | |||
805 | pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); | ||
806 | switch (cmd) { | ||
807 | case CLOSE_CHANNEL: | ||
808 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
809 | if (test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
810 | spin_lock_irqsave(&card->lock, flags); | ||
811 | mISDN_freebchannel(bch); | ||
812 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
813 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
814 | mode_tiger(bc, ISDN_P_NONE); | ||
815 | spin_unlock_irqrestore(&card->lock, flags); | ||
816 | } | ||
817 | ch->protocol = ISDN_P_NONE; | ||
818 | ch->peer = NULL; | ||
819 | module_put(THIS_MODULE); | ||
820 | ret = 0; | ||
821 | break; | ||
822 | case CONTROL_CHANNEL: | ||
823 | ret = channel_bctrl(bc, arg); | ||
824 | break; | ||
825 | default: | ||
826 | pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd); | ||
827 | } | ||
828 | return ret; | ||
829 | } | ||
830 | |||
831 | static int | ||
832 | channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) | ||
833 | { | ||
834 | int ret = 0; | ||
835 | |||
836 | switch (cq->op) { | ||
837 | case MISDN_CTRL_GETOP: | ||
838 | cq->op = MISDN_CTRL_LOOP; | ||
839 | break; | ||
840 | case MISDN_CTRL_LOOP: | ||
841 | /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ | ||
842 | if (cq->channel < 0 || cq->channel > 3) { | ||
843 | ret = -EINVAL; | ||
844 | break; | ||
845 | } | ||
846 | ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel); | ||
847 | break; | ||
848 | default: | ||
849 | pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); | ||
850 | ret = -EINVAL; | ||
851 | break; | ||
852 | } | ||
853 | return ret; | ||
854 | } | ||
855 | |||
856 | static int | ||
857 | open_bchannel(struct tiger_hw *card, struct channel_req *rq) | ||
858 | { | ||
859 | struct bchannel *bch; | ||
860 | |||
861 | if (rq->adr.channel > 2) | ||
862 | return -EINVAL; | ||
863 | if (rq->protocol == ISDN_P_NONE) | ||
864 | return -EINVAL; | ||
865 | bch = &card->bc[rq->adr.channel - 1].bch; | ||
866 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
867 | return -EBUSY; /* b-channel can be only open once */ | ||
868 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | ||
869 | bch->ch.protocol = rq->protocol; | ||
870 | rq->ch = &bch->ch; | ||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | /* | ||
875 | * device control function | ||
876 | */ | ||
877 | static int | ||
878 | nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
879 | { | ||
880 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
881 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
882 | struct tiger_hw *card = dch->hw; | ||
883 | struct channel_req *rq; | ||
884 | int err = 0; | ||
885 | |||
886 | pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); | ||
887 | switch (cmd) { | ||
888 | case OPEN_CHANNEL: | ||
889 | rq = arg; | ||
890 | if (rq->protocol == ISDN_P_TE_S0) | ||
891 | err = card->isac.open(&card->isac, rq); | ||
892 | else | ||
893 | err = open_bchannel(card, rq); | ||
894 | if (err) | ||
895 | break; | ||
896 | if (!try_module_get(THIS_MODULE)) | ||
897 | pr_info("%s: cannot get module\n", card->name); | ||
898 | break; | ||
899 | case CLOSE_CHANNEL: | ||
900 | pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id, | ||
901 | __builtin_return_address(0)); | ||
902 | module_put(THIS_MODULE); | ||
903 | break; | ||
904 | case CONTROL_CHANNEL: | ||
905 | err = channel_ctrl(card, arg); | ||
906 | break; | ||
907 | default: | ||
908 | pr_debug("%s: %s unknown command %x\n", | ||
909 | card->name, __func__, cmd); | ||
910 | return -EINVAL; | ||
911 | } | ||
912 | return err; | ||
913 | } | ||
914 | |||
915 | static int | ||
916 | nj_init_card(struct tiger_hw *card) | ||
917 | { | ||
918 | u_long flags; | ||
919 | int ret; | ||
920 | |||
921 | spin_lock_irqsave(&card->lock, flags); | ||
922 | nj_disable_hwirq(card); | ||
923 | spin_unlock_irqrestore(&card->lock, flags); | ||
924 | |||
925 | card->irq = card->pdev->irq; | ||
926 | if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) { | ||
927 | pr_info("%s: couldn't get interrupt %d\n", | ||
928 | card->name, card->irq); | ||
929 | card->irq = -1; | ||
930 | return -EIO; | ||
931 | } | ||
932 | |||
933 | spin_lock_irqsave(&card->lock, flags); | ||
934 | nj_reset(card); | ||
935 | ret = card->isac.init(&card->isac); | ||
936 | if (ret) | ||
937 | goto error; | ||
938 | ret = inittiger(card); | ||
939 | if (ret) | ||
940 | goto error; | ||
941 | mode_tiger(&card->bc[0], ISDN_P_NONE); | ||
942 | mode_tiger(&card->bc[1], ISDN_P_NONE); | ||
943 | error: | ||
944 | spin_unlock_irqrestore(&card->lock, flags); | ||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | |||
949 | static void | ||
950 | nj_release(struct tiger_hw *card) | ||
951 | { | ||
952 | u_long flags; | ||
953 | int i; | ||
954 | |||
955 | if (card->base_s) { | ||
956 | spin_lock_irqsave(&card->lock, flags); | ||
957 | nj_disable_hwirq(card); | ||
958 | mode_tiger(&card->bc[0], ISDN_P_NONE); | ||
959 | mode_tiger(&card->bc[1], ISDN_P_NONE); | ||
960 | card->isac.release(&card->isac); | ||
961 | spin_unlock_irqrestore(&card->lock, flags); | ||
962 | release_region(card->base, card->base_s); | ||
963 | card->base_s = 0; | ||
964 | } | ||
965 | if (card->irq > 0) | ||
966 | free_irq(card->irq, card); | ||
967 | if (card->isac.dch.dev.dev.class) | ||
968 | mISDN_unregister_device(&card->isac.dch.dev); | ||
969 | |||
970 | for (i = 0; i < 2; i++) { | ||
971 | mISDN_freebchannel(&card->bc[i].bch); | ||
972 | kfree(card->bc[i].hsbuf); | ||
973 | kfree(card->bc[i].hrbuf); | ||
974 | } | ||
975 | if (card->dma_p) | ||
976 | pci_free_consistent(card->pdev, NJ_DMA_SIZE, | ||
977 | card->dma_p, card->dma); | ||
978 | write_lock_irqsave(&card_lock, flags); | ||
979 | list_del(&card->list); | ||
980 | write_unlock_irqrestore(&card_lock, flags); | ||
981 | pci_clear_master(card->pdev); | ||
982 | pci_disable_device(card->pdev); | ||
983 | pci_set_drvdata(card->pdev, NULL); | ||
984 | kfree(card); | ||
985 | } | ||
986 | |||
987 | |||
988 | static int | ||
989 | nj_setup(struct tiger_hw *card) | ||
990 | { | ||
991 | card->base = pci_resource_start(card->pdev, 0); | ||
992 | card->base_s = pci_resource_len(card->pdev, 0); | ||
993 | if (!request_region(card->base, card->base_s, card->name)) { | ||
994 | pr_info("%s: NETjet config port %#x-%#x already in use\n", | ||
995 | card->name, card->base, | ||
996 | (u32)(card->base + card->base_s - 1)); | ||
997 | card->base_s = 0; | ||
998 | return -EIO; | ||
999 | } | ||
1000 | ASSIGN_FUNC(nj, ISAC, card->isac); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | static int __devinit | ||
1006 | setup_instance(struct tiger_hw *card) | ||
1007 | { | ||
1008 | int i, err; | ||
1009 | u_long flags; | ||
1010 | |||
1011 | snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1); | ||
1012 | write_lock_irqsave(&card_lock, flags); | ||
1013 | list_add_tail(&card->list, &Cards); | ||
1014 | write_unlock_irqrestore(&card_lock, flags); | ||
1015 | |||
1016 | _set_debug(card); | ||
1017 | card->isac.name = card->name; | ||
1018 | spin_lock_init(&card->lock); | ||
1019 | card->isac.hwlock = &card->lock; | ||
1020 | mISDNisac_init(&card->isac, card); | ||
1021 | |||
1022 | card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1023 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
1024 | card->isac.dch.dev.D.ctrl = nj_dctrl; | ||
1025 | for (i = 0; i < 2; i++) { | ||
1026 | card->bc[i].bch.nr = i + 1; | ||
1027 | set_channelmap(i + 1, card->isac.dch.dev.channelmap); | ||
1028 | mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); | ||
1029 | card->bc[i].bch.hw = card; | ||
1030 | card->bc[i].bch.ch.send = nj_l2l1B; | ||
1031 | card->bc[i].bch.ch.ctrl = nj_bctrl; | ||
1032 | card->bc[i].bch.ch.nr = i + 1; | ||
1033 | list_add(&card->bc[i].bch.ch.list, | ||
1034 | &card->isac.dch.dev.bchannels); | ||
1035 | card->bc[i].bch.hw = card; | ||
1036 | } | ||
1037 | err = nj_setup(card); | ||
1038 | if (err) | ||
1039 | goto error; | ||
1040 | err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, | ||
1041 | card->name); | ||
1042 | if (err) | ||
1043 | goto error; | ||
1044 | err = nj_init_card(card); | ||
1045 | if (!err) { | ||
1046 | nj_cnt++; | ||
1047 | pr_notice("Netjet %d cards installed\n", nj_cnt); | ||
1048 | return 0; | ||
1049 | } | ||
1050 | error: | ||
1051 | nj_release(card); | ||
1052 | return err; | ||
1053 | } | ||
1054 | |||
1055 | static int __devinit | ||
1056 | nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
1057 | { | ||
1058 | int err = -ENOMEM; | ||
1059 | int cfg; | ||
1060 | struct tiger_hw *card; | ||
1061 | |||
1062 | if (pdev->subsystem_vendor == 0x8086 && | ||
1063 | pdev->subsystem_device == 0x0003) { | ||
1064 | pr_notice("Netjet: Digium X100P/X101P not handled\n"); | ||
1065 | return -ENODEV; | ||
1066 | } | ||
1067 | |||
1068 | if (pdev->subsystem_vendor == 0x55 && | ||
1069 | pdev->subsystem_device == 0x02) { | ||
1070 | pr_notice("Netjet: Enter!Now not handled yet\n"); | ||
1071 | return -ENODEV; | ||
1072 | } | ||
1073 | |||
1074 | card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC); | ||
1075 | if (!card) { | ||
1076 | pr_info("No kmem for Netjet\n"); | ||
1077 | return err; | ||
1078 | } | ||
1079 | |||
1080 | card->pdev = pdev; | ||
1081 | |||
1082 | err = pci_enable_device(pdev); | ||
1083 | if (err) { | ||
1084 | kfree(card); | ||
1085 | return err; | ||
1086 | } | ||
1087 | |||
1088 | printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n", | ||
1089 | pci_name(pdev)); | ||
1090 | |||
1091 | pci_set_master(pdev); | ||
1092 | |||
1093 | /* the TJ300 and TJ320 must be detected, the IRQ handling is different | ||
1094 | * unfortunately the chips use the same device ID, but the TJ320 has | ||
1095 | * the bit20 in status PCI cfg register set | ||
1096 | */ | ||
1097 | pci_read_config_dword(pdev, 0x04, &cfg); | ||
1098 | if (cfg & 0x00100000) | ||
1099 | card->typ = NETJET_S_TJ320; | ||
1100 | else | ||
1101 | card->typ = NETJET_S_TJ300; | ||
1102 | |||
1103 | card->base = pci_resource_start(pdev, 0); | ||
1104 | card->irq = pdev->irq; | ||
1105 | pci_set_drvdata(pdev, card); | ||
1106 | err = setup_instance(card); | ||
1107 | if (err) | ||
1108 | pci_set_drvdata(pdev, NULL); | ||
1109 | |||
1110 | return err; | ||
1111 | } | ||
1112 | |||
1113 | |||
1114 | static void __devexit nj_remove(struct pci_dev *pdev) | ||
1115 | { | ||
1116 | struct tiger_hw *card = pci_get_drvdata(pdev); | ||
1117 | |||
1118 | if (card) | ||
1119 | nj_release(card); | ||
1120 | else | ||
1121 | pr_info("%s drvdata already removed\n", __func__); | ||
1122 | } | ||
1123 | |||
1124 | /* We cannot select cards with PCI_SUB... IDs, since here are cards with | ||
1125 | * SUB IDs set to PCI_ANY_ID, so we need to match all and reject | ||
1126 | * known other cards which not work with this driver - see probe function */ | ||
1127 | static struct pci_device_id nj_pci_ids[] __devinitdata = { | ||
1128 | { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300, | ||
1129 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
1130 | { } | ||
1131 | }; | ||
1132 | MODULE_DEVICE_TABLE(pci, nj_pci_ids); | ||
1133 | |||
1134 | static struct pci_driver nj_driver = { | ||
1135 | .name = "netjet", | ||
1136 | .probe = nj_probe, | ||
1137 | .remove = __devexit_p(nj_remove), | ||
1138 | .id_table = nj_pci_ids, | ||
1139 | }; | ||
1140 | |||
1141 | static int __init nj_init(void) | ||
1142 | { | ||
1143 | int err; | ||
1144 | |||
1145 | pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV); | ||
1146 | err = pci_register_driver(&nj_driver); | ||
1147 | return err; | ||
1148 | } | ||
1149 | |||
1150 | static void __exit nj_cleanup(void) | ||
1151 | { | ||
1152 | pci_unregister_driver(&nj_driver); | ||
1153 | } | ||
1154 | |||
1155 | module_init(nj_init); | ||
1156 | module_exit(nj_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h new file mode 100644 index 000000000000..d061ff995607 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/netjet.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * NETjet common header file | ||
3 | * | ||
4 | * Author Karsten Keil | ||
5 | * based on work of Matt Henderson and Daniel Potts, | ||
6 | * Traverse Technologies P/L www.traverse.com.au | ||
7 | * | ||
8 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #define NJ_CTRL 0x00 | ||
26 | #define NJ_DMACTRL 0x01 | ||
27 | #define NJ_AUXCTRL 0x02 | ||
28 | #define NJ_AUXDATA 0x03 | ||
29 | #define NJ_IRQMASK0 0x04 | ||
30 | #define NJ_IRQMASK1 0x05 | ||
31 | #define NJ_IRQSTAT0 0x06 | ||
32 | #define NJ_IRQSTAT1 0x07 | ||
33 | #define NJ_DMA_READ_START 0x08 | ||
34 | #define NJ_DMA_READ_IRQ 0x0c | ||
35 | #define NJ_DMA_READ_END 0x10 | ||
36 | #define NJ_DMA_READ_ADR 0x14 | ||
37 | #define NJ_DMA_WRITE_START 0x18 | ||
38 | #define NJ_DMA_WRITE_IRQ 0x1c | ||
39 | #define NJ_DMA_WRITE_END 0x20 | ||
40 | #define NJ_DMA_WRITE_ADR 0x24 | ||
41 | #define NJ_PULSE_CNT 0x28 | ||
42 | |||
43 | #define NJ_ISAC_OFF 0xc0 | ||
44 | #define NJ_ISACIRQ 0x10 | ||
45 | |||
46 | #define NJ_IRQM0_RD_MASK 0x03 | ||
47 | #define NJ_IRQM0_RD_IRQ 0x01 | ||
48 | #define NJ_IRQM0_RD_END 0x02 | ||
49 | #define NJ_IRQM0_WR_MASK 0x0c | ||
50 | #define NJ_IRQM0_WR_IRQ 0x04 | ||
51 | #define NJ_IRQM0_WR_END 0x08 | ||
52 | |||
53 | /* one page here is no need to be smaller */ | ||
54 | #define NJ_DMA_SIZE 4096 | ||
55 | /* 2 * 64 byte is a compromise between IRQ count and latency */ | ||
56 | #define NJ_DMA_RXSIZE 128 /* 2 * 64 */ | ||
57 | #define NJ_DMA_TXSIZE 128 /* 2 * 64 */ | ||
58 | |||
diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c new file mode 100644 index 000000000000..ff3a4e290da3 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/speedfax.c | |||
@@ -0,0 +1,526 @@ | |||
1 | /* | ||
2 | * speedfax.c low level stuff for Sedlbauer Speedfax+ cards | ||
3 | * based on the ISAR DSP | ||
4 | * Thanks to Sedlbauer AG for informations and HW | ||
5 | * | ||
6 | * Author Karsten Keil <keil@isdn4linux.de> | ||
7 | * | ||
8 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/mISDNhw.h> | ||
29 | #include <linux/firmware.h> | ||
30 | #include "ipac.h" | ||
31 | #include "isar.h" | ||
32 | |||
33 | #define SPEEDFAX_REV "2.0" | ||
34 | |||
35 | #define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 | ||
36 | #define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 | ||
37 | #define PCI_SUB_ID_SEDLBAUER 0x01 | ||
38 | |||
39 | #define SFAX_PCI_ADDR 0xc8 | ||
40 | #define SFAX_PCI_ISAC 0xd0 | ||
41 | #define SFAX_PCI_ISAR 0xe0 | ||
42 | |||
43 | /* TIGER 100 Registers */ | ||
44 | |||
45 | #define TIGER_RESET_ADDR 0x00 | ||
46 | #define TIGER_EXTERN_RESET_ON 0x01 | ||
47 | #define TIGER_EXTERN_RESET_OFF 0x00 | ||
48 | #define TIGER_AUX_CTRL 0x02 | ||
49 | #define TIGER_AUX_DATA 0x03 | ||
50 | #define TIGER_AUX_IRQMASK 0x05 | ||
51 | #define TIGER_AUX_STATUS 0x07 | ||
52 | |||
53 | /* Tiger AUX BITs */ | ||
54 | #define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */ | ||
55 | #define SFAX_ISAR_RESET_BIT_OFF 0x00 | ||
56 | #define SFAX_ISAR_RESET_BIT_ON 0x01 | ||
57 | #define SFAX_TIGER_IRQ_BIT 0x02 | ||
58 | #define SFAX_LED1_BIT 0x08 | ||
59 | #define SFAX_LED2_BIT 0x10 | ||
60 | |||
61 | #define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON) | ||
62 | #define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT) | ||
63 | |||
64 | static int sfax_cnt; | ||
65 | static u32 debug; | ||
66 | static u32 irqloops = 4; | ||
67 | |||
68 | struct sfax_hw { | ||
69 | struct list_head list; | ||
70 | struct pci_dev *pdev; | ||
71 | char name[MISDN_MAX_IDLEN]; | ||
72 | u32 irq; | ||
73 | u32 irqcnt; | ||
74 | u32 cfg; | ||
75 | struct _ioport p_isac; | ||
76 | struct _ioport p_isar; | ||
77 | u8 aux_data; | ||
78 | spinlock_t lock; /* HW access lock */ | ||
79 | struct isac_hw isac; | ||
80 | struct isar_hw isar; | ||
81 | }; | ||
82 | |||
83 | static LIST_HEAD(Cards); | ||
84 | static DEFINE_RWLOCK(card_lock); /* protect Cards */ | ||
85 | |||
86 | static void | ||
87 | _set_debug(struct sfax_hw *card) | ||
88 | { | ||
89 | card->isac.dch.debug = debug; | ||
90 | card->isar.ch[0].bch.debug = debug; | ||
91 | card->isar.ch[1].bch.debug = debug; | ||
92 | } | ||
93 | |||
94 | static int | ||
95 | set_debug(const char *val, struct kernel_param *kp) | ||
96 | { | ||
97 | int ret; | ||
98 | struct sfax_hw *card; | ||
99 | |||
100 | ret = param_set_uint(val, kp); | ||
101 | if (!ret) { | ||
102 | read_lock(&card_lock); | ||
103 | list_for_each_entry(card, &Cards, list) | ||
104 | _set_debug(card); | ||
105 | read_unlock(&card_lock); | ||
106 | } | ||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | MODULE_AUTHOR("Karsten Keil"); | ||
111 | MODULE_LICENSE("GPL v2"); | ||
112 | MODULE_VERSION(SPEEDFAX_REV); | ||
113 | module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); | ||
114 | MODULE_PARM_DESC(debug, "Speedfax debug mask"); | ||
115 | module_param(irqloops, uint, S_IRUGO | S_IWUSR); | ||
116 | MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)"); | ||
117 | |||
118 | IOFUNC_IND(ISAC, sfax_hw, p_isac) | ||
119 | IOFUNC_IND(ISAR, sfax_hw, p_isar) | ||
120 | |||
121 | static irqreturn_t | ||
122 | speedfax_irq(int intno, void *dev_id) | ||
123 | { | ||
124 | struct sfax_hw *sf = dev_id; | ||
125 | u8 val; | ||
126 | int cnt = irqloops; | ||
127 | |||
128 | spin_lock(&sf->lock); | ||
129 | val = inb(sf->cfg + TIGER_AUX_STATUS); | ||
130 | if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */ | ||
131 | spin_unlock(&sf->lock); | ||
132 | return IRQ_NONE; /* shared */ | ||
133 | } | ||
134 | sf->irqcnt++; | ||
135 | val = ReadISAR_IND(sf, ISAR_IRQBIT); | ||
136 | Start_ISAR: | ||
137 | if (val & ISAR_IRQSTA) | ||
138 | mISDNisar_irq(&sf->isar); | ||
139 | val = ReadISAC_IND(sf, ISAC_ISTA); | ||
140 | if (val) | ||
141 | mISDNisac_irq(&sf->isac, val); | ||
142 | val = ReadISAR_IND(sf, ISAR_IRQBIT); | ||
143 | if ((val & ISAR_IRQSTA) && cnt--) | ||
144 | goto Start_ISAR; | ||
145 | if (cnt < irqloops) | ||
146 | pr_debug("%s: %d irqloops cpu%d\n", sf->name, | ||
147 | irqloops - cnt, smp_processor_id()); | ||
148 | if (irqloops && !cnt) | ||
149 | pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name, | ||
150 | irqloops, smp_processor_id()); | ||
151 | spin_unlock(&sf->lock); | ||
152 | return IRQ_HANDLED; | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | enable_hwirq(struct sfax_hw *sf) | ||
157 | { | ||
158 | WriteISAC_IND(sf, ISAC_MASK, 0); | ||
159 | WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK); | ||
160 | outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK); | ||
161 | } | ||
162 | |||
163 | static void | ||
164 | disable_hwirq(struct sfax_hw *sf) | ||
165 | { | ||
166 | WriteISAC_IND(sf, ISAC_MASK, 0xFF); | ||
167 | WriteISAR_IND(sf, ISAR_IRQBIT, 0); | ||
168 | outb(0, sf->cfg + TIGER_AUX_IRQMASK); | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | reset_speedfax(struct sfax_hw *sf) | ||
173 | { | ||
174 | |||
175 | pr_debug("%s: resetting card\n", sf->name); | ||
176 | outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR); | ||
177 | outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA); | ||
178 | mdelay(1); | ||
179 | outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR); | ||
180 | sf->aux_data = SFAX_PCI_RESET_OFF; | ||
181 | outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); | ||
182 | mdelay(1); | ||
183 | } | ||
184 | |||
185 | static int | ||
186 | sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg) | ||
187 | { | ||
188 | int ret = 0; | ||
189 | |||
190 | switch (cmd) { | ||
191 | case HW_RESET_REQ: | ||
192 | reset_speedfax(sf); | ||
193 | break; | ||
194 | case HW_ACTIVATE_IND: | ||
195 | if (arg & 1) | ||
196 | sf->aux_data &= ~SFAX_LED1_BIT; | ||
197 | if (arg & 2) | ||
198 | sf->aux_data &= ~SFAX_LED2_BIT; | ||
199 | outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); | ||
200 | break; | ||
201 | case HW_DEACT_IND: | ||
202 | if (arg & 1) | ||
203 | sf->aux_data |= SFAX_LED1_BIT; | ||
204 | if (arg & 2) | ||
205 | sf->aux_data |= SFAX_LED2_BIT; | ||
206 | outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); | ||
207 | break; | ||
208 | default: | ||
209 | pr_info("%s: %s unknown command %x %lx\n", | ||
210 | sf->name, __func__, cmd, arg); | ||
211 | ret = -EINVAL; | ||
212 | break; | ||
213 | } | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static int | ||
218 | channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) | ||
219 | { | ||
220 | int ret = 0; | ||
221 | |||
222 | switch (cq->op) { | ||
223 | case MISDN_CTRL_GETOP: | ||
224 | cq->op = MISDN_CTRL_LOOP; | ||
225 | break; | ||
226 | case MISDN_CTRL_LOOP: | ||
227 | /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ | ||
228 | if (cq->channel < 0 || cq->channel > 3) { | ||
229 | ret = -EINVAL; | ||
230 | break; | ||
231 | } | ||
232 | ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); | ||
233 | break; | ||
234 | default: | ||
235 | pr_info("%s: unknown Op %x\n", sf->name, cq->op); | ||
236 | ret = -EINVAL; | ||
237 | break; | ||
238 | } | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int | ||
243 | sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
244 | { | ||
245 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
246 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
247 | struct sfax_hw *sf = dch->hw; | ||
248 | struct channel_req *rq; | ||
249 | int err = 0; | ||
250 | |||
251 | pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg); | ||
252 | switch (cmd) { | ||
253 | case OPEN_CHANNEL: | ||
254 | rq = arg; | ||
255 | if (rq->protocol == ISDN_P_TE_S0) | ||
256 | err = sf->isac.open(&sf->isac, rq); | ||
257 | else | ||
258 | err = sf->isar.open(&sf->isar, rq); | ||
259 | if (err) | ||
260 | break; | ||
261 | if (!try_module_get(THIS_MODULE)) | ||
262 | pr_info("%s: cannot get module\n", sf->name); | ||
263 | break; | ||
264 | case CLOSE_CHANNEL: | ||
265 | pr_debug("%s: dev(%d) close from %p\n", sf->name, | ||
266 | dch->dev.id, __builtin_return_address(0)); | ||
267 | module_put(THIS_MODULE); | ||
268 | break; | ||
269 | case CONTROL_CHANNEL: | ||
270 | err = channel_ctrl(sf, arg); | ||
271 | break; | ||
272 | default: | ||
273 | pr_debug("%s: unknown command %x\n", sf->name, cmd); | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | return err; | ||
277 | } | ||
278 | |||
279 | static int __devinit | ||
280 | init_card(struct sfax_hw *sf) | ||
281 | { | ||
282 | int ret, cnt = 3; | ||
283 | u_long flags; | ||
284 | |||
285 | ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf); | ||
286 | if (ret) { | ||
287 | pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq); | ||
288 | return ret; | ||
289 | } | ||
290 | while (cnt--) { | ||
291 | spin_lock_irqsave(&sf->lock, flags); | ||
292 | ret = sf->isac.init(&sf->isac); | ||
293 | if (ret) { | ||
294 | spin_unlock_irqrestore(&sf->lock, flags); | ||
295 | pr_info("%s: ISAC init failed with %d\n", | ||
296 | sf->name, ret); | ||
297 | break; | ||
298 | } | ||
299 | enable_hwirq(sf); | ||
300 | /* RESET Receiver and Transmitter */ | ||
301 | WriteISAC_IND(sf, ISAC_CMDR, 0x41); | ||
302 | spin_unlock_irqrestore(&sf->lock, flags); | ||
303 | msleep_interruptible(10); | ||
304 | if (debug & DEBUG_HW) | ||
305 | pr_notice("%s: IRQ %d count %d\n", sf->name, | ||
306 | sf->irq, sf->irqcnt); | ||
307 | if (!sf->irqcnt) { | ||
308 | pr_info("%s: IRQ(%d) got no requests during init %d\n", | ||
309 | sf->name, sf->irq, 3 - cnt); | ||
310 | } else | ||
311 | return 0; | ||
312 | } | ||
313 | free_irq(sf->irq, sf); | ||
314 | return -EIO; | ||
315 | } | ||
316 | |||
317 | |||
318 | static int __devinit | ||
319 | setup_speedfax(struct sfax_hw *sf) | ||
320 | { | ||
321 | u_long flags; | ||
322 | |||
323 | if (!request_region(sf->cfg, 256, sf->name)) { | ||
324 | pr_info("mISDN: %s config port %x-%x already in use\n", | ||
325 | sf->name, sf->cfg, sf->cfg + 255); | ||
326 | return -EIO; | ||
327 | } | ||
328 | outb(0xff, sf->cfg); | ||
329 | outb(0, sf->cfg); | ||
330 | outb(0xdd, sf->cfg + TIGER_AUX_CTRL); | ||
331 | outb(0, sf->cfg + TIGER_AUX_IRQMASK); | ||
332 | |||
333 | sf->isac.type = IPAC_TYPE_ISAC; | ||
334 | sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR; | ||
335 | sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC; | ||
336 | sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR; | ||
337 | sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR; | ||
338 | ASSIGN_FUNC(IND, ISAC, sf->isac); | ||
339 | ASSIGN_FUNC(IND, ISAR, sf->isar); | ||
340 | spin_lock_irqsave(&sf->lock, flags); | ||
341 | reset_speedfax(sf); | ||
342 | disable_hwirq(sf); | ||
343 | spin_unlock_irqrestore(&sf->lock, flags); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void | ||
348 | release_card(struct sfax_hw *card) { | ||
349 | u_long flags; | ||
350 | |||
351 | spin_lock_irqsave(&card->lock, flags); | ||
352 | disable_hwirq(card); | ||
353 | spin_unlock_irqrestore(&card->lock, flags); | ||
354 | card->isac.release(&card->isac); | ||
355 | free_irq(card->irq, card); | ||
356 | card->isar.release(&card->isar); | ||
357 | mISDN_unregister_device(&card->isac.dch.dev); | ||
358 | release_region(card->cfg, 256); | ||
359 | pci_disable_device(card->pdev); | ||
360 | pci_set_drvdata(card->pdev, NULL); | ||
361 | write_lock_irqsave(&card_lock, flags); | ||
362 | list_del(&card->list); | ||
363 | write_unlock_irqrestore(&card_lock, flags); | ||
364 | kfree(card); | ||
365 | sfax_cnt--; | ||
366 | } | ||
367 | |||
368 | static int __devinit | ||
369 | setup_instance(struct sfax_hw *card) | ||
370 | { | ||
371 | const struct firmware *firmware; | ||
372 | int i, err; | ||
373 | u_long flags; | ||
374 | |||
375 | snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1); | ||
376 | write_lock_irqsave(&card_lock, flags); | ||
377 | list_add_tail(&card->list, &Cards); | ||
378 | write_unlock_irqrestore(&card_lock, flags); | ||
379 | _set_debug(card); | ||
380 | spin_lock_init(&card->lock); | ||
381 | card->isac.hwlock = &card->lock; | ||
382 | card->isar.hwlock = &card->lock; | ||
383 | card->isar.ctrl = (void *)&sfax_ctrl; | ||
384 | card->isac.name = card->name; | ||
385 | card->isar.name = card->name; | ||
386 | card->isar.owner = THIS_MODULE; | ||
387 | |||
388 | err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev); | ||
389 | if (err < 0) { | ||
390 | pr_info("%s: firmware request failed %d\n", | ||
391 | card->name, err); | ||
392 | goto error_fw; | ||
393 | } | ||
394 | if (debug & DEBUG_HW) | ||
395 | pr_notice("%s: got firmware %zu bytes\n", | ||
396 | card->name, firmware->size); | ||
397 | |||
398 | mISDNisac_init(&card->isac, card); | ||
399 | |||
400 | card->isac.dch.dev.D.ctrl = sfax_dctrl; | ||
401 | card->isac.dch.dev.Bprotocols = | ||
402 | mISDNisar_init(&card->isar, card); | ||
403 | for (i = 0; i < 2; i++) { | ||
404 | set_channelmap(i + 1, card->isac.dch.dev.channelmap); | ||
405 | list_add(&card->isar.ch[i].bch.ch.list, | ||
406 | &card->isac.dch.dev.bchannels); | ||
407 | } | ||
408 | |||
409 | err = setup_speedfax(card); | ||
410 | if (err) | ||
411 | goto error_setup; | ||
412 | err = card->isar.init(&card->isar); | ||
413 | if (err) | ||
414 | goto error; | ||
415 | err = mISDN_register_device(&card->isac.dch.dev, | ||
416 | &card->pdev->dev, card->name); | ||
417 | if (err) | ||
418 | goto error; | ||
419 | err = init_card(card); | ||
420 | if (err) | ||
421 | goto error_init; | ||
422 | err = card->isar.firmware(&card->isar, firmware->data, firmware->size); | ||
423 | if (!err) { | ||
424 | release_firmware(firmware); | ||
425 | sfax_cnt++; | ||
426 | pr_notice("SpeedFax %d cards installed\n", sfax_cnt); | ||
427 | return 0; | ||
428 | } | ||
429 | disable_hwirq(card); | ||
430 | free_irq(card->irq, card); | ||
431 | error_init: | ||
432 | mISDN_unregister_device(&card->isac.dch.dev); | ||
433 | error: | ||
434 | release_region(card->cfg, 256); | ||
435 | error_setup: | ||
436 | card->isac.release(&card->isac); | ||
437 | card->isar.release(&card->isar); | ||
438 | release_firmware(firmware); | ||
439 | error_fw: | ||
440 | pci_disable_device(card->pdev); | ||
441 | write_lock_irqsave(&card_lock, flags); | ||
442 | list_del(&card->list); | ||
443 | write_unlock_irqrestore(&card_lock, flags); | ||
444 | kfree(card); | ||
445 | return err; | ||
446 | } | ||
447 | |||
448 | static int __devinit | ||
449 | sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
450 | { | ||
451 | int err = -ENOMEM; | ||
452 | struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL); | ||
453 | |||
454 | if (!card) { | ||
455 | pr_info("No memory for Speedfax+ PCI\n"); | ||
456 | return err; | ||
457 | } | ||
458 | card->pdev = pdev; | ||
459 | err = pci_enable_device(pdev); | ||
460 | if (err) { | ||
461 | kfree(card); | ||
462 | return err; | ||
463 | } | ||
464 | |||
465 | pr_notice("mISDN: Speedfax found adapter %s at %s\n", | ||
466 | (char *)ent->driver_data, pci_name(pdev)); | ||
467 | |||
468 | card->cfg = pci_resource_start(pdev, 0); | ||
469 | card->irq = pdev->irq; | ||
470 | pci_set_drvdata(pdev, card); | ||
471 | err = setup_instance(card); | ||
472 | if (err) | ||
473 | pci_set_drvdata(pdev, NULL); | ||
474 | return err; | ||
475 | } | ||
476 | |||
477 | static void __devexit | ||
478 | sfax_remove_pci(struct pci_dev *pdev) | ||
479 | { | ||
480 | struct sfax_hw *card = pci_get_drvdata(pdev); | ||
481 | |||
482 | if (card) | ||
483 | release_card(card); | ||
484 | else | ||
485 | pr_debug("%s: drvdata allready removed\n", __func__); | ||
486 | } | ||
487 | |||
488 | static struct pci_device_id sfaxpci_ids[] __devinitdata = { | ||
489 | { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, | ||
490 | PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER, | ||
491 | 0, 0, (unsigned long) "Pyramid Speedfax + PCI" | ||
492 | }, | ||
493 | { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, | ||
494 | PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER, | ||
495 | 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" | ||
496 | }, | ||
497 | { } | ||
498 | }; | ||
499 | MODULE_DEVICE_TABLE(pci, sfaxpci_ids); | ||
500 | |||
501 | static struct pci_driver sfaxpci_driver = { | ||
502 | .name = "speedfax+ pci", | ||
503 | .probe = sfaxpci_probe, | ||
504 | .remove = __devexit_p(sfax_remove_pci), | ||
505 | .id_table = sfaxpci_ids, | ||
506 | }; | ||
507 | |||
508 | static int __init | ||
509 | Speedfax_init(void) | ||
510 | { | ||
511 | int err; | ||
512 | |||
513 | pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n", | ||
514 | SPEEDFAX_REV); | ||
515 | err = pci_register_driver(&sfaxpci_driver); | ||
516 | return err; | ||
517 | } | ||
518 | |||
519 | static void __exit | ||
520 | Speedfax_cleanup(void) | ||
521 | { | ||
522 | pci_unregister_driver(&sfaxpci_driver); | ||
523 | } | ||
524 | |||
525 | module_init(Speedfax_init); | ||
526 | module_exit(Speedfax_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c new file mode 100644 index 000000000000..d3f1077b709b --- /dev/null +++ b/drivers/isdn/hardware/mISDN/w6692.c | |||
@@ -0,0 +1,1440 @@ | |||
1 | /* | ||
2 | * w6692.c mISDN driver for Winbond w6692 based cards | ||
3 | * | ||
4 | * Author Karsten Keil <kkeil@suse.de> | ||
5 | * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz> | ||
6 | * | ||
7 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/mISDNhw.h> | ||
28 | #include "w6692.h" | ||
29 | |||
30 | #define W6692_REV "2.0" | ||
31 | |||
32 | #define DBUSY_TIMER_VALUE 80 | ||
33 | |||
34 | enum { | ||
35 | W6692_ASUS, | ||
36 | W6692_WINBOND, | ||
37 | W6692_USR | ||
38 | }; | ||
39 | |||
40 | /* private data in the PCI devices list */ | ||
41 | struct w6692map { | ||
42 | u_int subtype; | ||
43 | char *name; | ||
44 | }; | ||
45 | |||
46 | static const struct w6692map w6692_map[] = | ||
47 | { | ||
48 | {W6692_ASUS, "Dynalink/AsusCom IS64PH"}, | ||
49 | {W6692_WINBOND, "Winbond W6692"}, | ||
50 | {W6692_USR, "USR W6692"} | ||
51 | }; | ||
52 | |||
53 | #ifndef PCI_VENDOR_ID_USR | ||
54 | #define PCI_VENDOR_ID_USR 0x16ec | ||
55 | #define PCI_DEVICE_ID_USR_6692 0x3409 | ||
56 | #endif | ||
57 | |||
58 | struct w6692_ch { | ||
59 | struct bchannel bch; | ||
60 | u32 addr; | ||
61 | struct timer_list timer; | ||
62 | u8 b_mode; | ||
63 | }; | ||
64 | |||
65 | struct w6692_hw { | ||
66 | struct list_head list; | ||
67 | struct pci_dev *pdev; | ||
68 | char name[MISDN_MAX_IDLEN]; | ||
69 | u32 irq; | ||
70 | u32 irqcnt; | ||
71 | u32 addr; | ||
72 | u32 fmask; /* feature mask - bit set per card nr */ | ||
73 | int subtype; | ||
74 | spinlock_t lock; /* hw lock */ | ||
75 | u8 imask; | ||
76 | u8 pctl; | ||
77 | u8 xaddr; | ||
78 | u8 xdata; | ||
79 | u8 state; | ||
80 | struct w6692_ch bc[2]; | ||
81 | struct dchannel dch; | ||
82 | char log[64]; | ||
83 | }; | ||
84 | |||
85 | static LIST_HEAD(Cards); | ||
86 | static DEFINE_RWLOCK(card_lock); /* protect Cards */ | ||
87 | |||
88 | static int w6692_cnt; | ||
89 | static int debug; | ||
90 | static u32 led; | ||
91 | static u32 pots; | ||
92 | |||
93 | static void | ||
94 | _set_debug(struct w6692_hw *card) | ||
95 | { | ||
96 | card->dch.debug = debug; | ||
97 | card->bc[0].bch.debug = debug; | ||
98 | card->bc[1].bch.debug = debug; | ||
99 | } | ||
100 | |||
101 | static int | ||
102 | set_debug(const char *val, struct kernel_param *kp) | ||
103 | { | ||
104 | int ret; | ||
105 | struct w6692_hw *card; | ||
106 | |||
107 | ret = param_set_uint(val, kp); | ||
108 | if (!ret) { | ||
109 | read_lock(&card_lock); | ||
110 | list_for_each_entry(card, &Cards, list) | ||
111 | _set_debug(card); | ||
112 | read_unlock(&card_lock); | ||
113 | } | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | MODULE_AUTHOR("Karsten Keil"); | ||
118 | MODULE_LICENSE("GPL v2"); | ||
119 | MODULE_VERSION(W6692_REV); | ||
120 | module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); | ||
121 | MODULE_PARM_DESC(debug, "W6692 debug mask"); | ||
122 | module_param(led, uint, S_IRUGO | S_IWUSR); | ||
123 | MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)"); | ||
124 | module_param(pots, uint, S_IRUGO | S_IWUSR); | ||
125 | MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)"); | ||
126 | |||
127 | static inline u8 | ||
128 | ReadW6692(struct w6692_hw *card, u8 offset) | ||
129 | { | ||
130 | return inb(card->addr + offset); | ||
131 | } | ||
132 | |||
133 | static inline void | ||
134 | WriteW6692(struct w6692_hw *card, u8 offset, u8 value) | ||
135 | { | ||
136 | outb(value, card->addr + offset); | ||
137 | } | ||
138 | |||
139 | static inline u8 | ||
140 | ReadW6692B(struct w6692_ch *bc, u8 offset) | ||
141 | { | ||
142 | return inb(bc->addr + offset); | ||
143 | } | ||
144 | |||
145 | static inline void | ||
146 | WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value) | ||
147 | { | ||
148 | outb(value, bc->addr + offset); | ||
149 | } | ||
150 | |||
151 | static void | ||
152 | enable_hwirq(struct w6692_hw *card) | ||
153 | { | ||
154 | WriteW6692(card, W_IMASK, card->imask); | ||
155 | } | ||
156 | |||
157 | static void | ||
158 | disable_hwirq(struct w6692_hw *card) | ||
159 | { | ||
160 | WriteW6692(card, W_IMASK, 0xff); | ||
161 | } | ||
162 | |||
163 | static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"}; | ||
164 | |||
165 | static void | ||
166 | W6692Version(struct w6692_hw *card) | ||
167 | { | ||
168 | int val; | ||
169 | |||
170 | val = ReadW6692(card, W_D_RBCH); | ||
171 | pr_notice("%s: Winbond W6692 version: %s\n", card->name, | ||
172 | W6692Ver[(val >> 6) & 3]); | ||
173 | } | ||
174 | |||
175 | static void | ||
176 | w6692_led_handler(struct w6692_hw *card, int on) | ||
177 | { | ||
178 | if ((!(card->fmask & led)) || card->subtype == W6692_USR) | ||
179 | return; | ||
180 | if (on) { | ||
181 | card->xdata &= 0xfb; /* LED ON */ | ||
182 | WriteW6692(card, W_XDATA, card->xdata); | ||
183 | } else { | ||
184 | card->xdata |= 0x04; /* LED OFF */ | ||
185 | WriteW6692(card, W_XDATA, card->xdata); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | ph_command(struct w6692_hw *card, u8 cmd) | ||
191 | { | ||
192 | pr_debug("%s: ph_command %x\n", card->name, cmd); | ||
193 | WriteW6692(card, W_CIX, cmd); | ||
194 | } | ||
195 | |||
196 | static void | ||
197 | W6692_new_ph(struct w6692_hw *card) | ||
198 | { | ||
199 | if (card->state == W_L1CMD_RST) | ||
200 | ph_command(card, W_L1CMD_DRC); | ||
201 | schedule_event(&card->dch, FLG_PHCHANGE); | ||
202 | } | ||
203 | |||
204 | static void | ||
205 | W6692_ph_bh(struct dchannel *dch) | ||
206 | { | ||
207 | struct w6692_hw *card = dch->hw; | ||
208 | |||
209 | switch (card->state) { | ||
210 | case W_L1CMD_RST: | ||
211 | dch->state = 0; | ||
212 | l1_event(dch->l1, HW_RESET_IND); | ||
213 | break; | ||
214 | case W_L1IND_CD: | ||
215 | dch->state = 3; | ||
216 | l1_event(dch->l1, HW_DEACT_CNF); | ||
217 | break; | ||
218 | case W_L1IND_DRD: | ||
219 | dch->state = 3; | ||
220 | l1_event(dch->l1, HW_DEACT_IND); | ||
221 | break; | ||
222 | case W_L1IND_CE: | ||
223 | dch->state = 4; | ||
224 | l1_event(dch->l1, HW_POWERUP_IND); | ||
225 | break; | ||
226 | case W_L1IND_LD: | ||
227 | if (dch->state <= 5) { | ||
228 | dch->state = 5; | ||
229 | l1_event(dch->l1, ANYSIGNAL); | ||
230 | } else { | ||
231 | dch->state = 8; | ||
232 | l1_event(dch->l1, LOSTFRAMING); | ||
233 | } | ||
234 | break; | ||
235 | case W_L1IND_ARD: | ||
236 | dch->state = 6; | ||
237 | l1_event(dch->l1, INFO2); | ||
238 | break; | ||
239 | case W_L1IND_AI8: | ||
240 | dch->state = 7; | ||
241 | l1_event(dch->l1, INFO4_P8); | ||
242 | break; | ||
243 | case W_L1IND_AI10: | ||
244 | dch->state = 7; | ||
245 | l1_event(dch->l1, INFO4_P10); | ||
246 | break; | ||
247 | default: | ||
248 | pr_debug("%s: TE unknown state %02x dch state %02x\n", | ||
249 | card->name, card->state, dch->state); | ||
250 | break; | ||
251 | } | ||
252 | pr_debug("%s: TE newstate %02x\n", card->name, dch->state); | ||
253 | } | ||
254 | |||
255 | static void | ||
256 | W6692_empty_Dfifo(struct w6692_hw *card, int count) | ||
257 | { | ||
258 | struct dchannel *dch = &card->dch; | ||
259 | u8 *ptr; | ||
260 | |||
261 | pr_debug("%s: empty_Dfifo %d\n", card->name, count); | ||
262 | if (!dch->rx_skb) { | ||
263 | dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC); | ||
264 | if (!dch->rx_skb) { | ||
265 | pr_info("%s: D receive out of memory\n", card->name); | ||
266 | WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); | ||
267 | return; | ||
268 | } | ||
269 | } | ||
270 | if ((dch->rx_skb->len + count) >= dch->maxlen) { | ||
271 | pr_debug("%s: empty_Dfifo overrun %d\n", card->name, | ||
272 | dch->rx_skb->len + count); | ||
273 | WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); | ||
274 | return; | ||
275 | } | ||
276 | ptr = skb_put(dch->rx_skb, count); | ||
277 | insb(card->addr + W_D_RFIFO, ptr, count); | ||
278 | WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); | ||
279 | if (debug & DEBUG_HW_DFIFO) { | ||
280 | snprintf(card->log, 63, "D-recv %s %d ", | ||
281 | card->name, count); | ||
282 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | static void | ||
287 | W6692_fill_Dfifo(struct w6692_hw *card) | ||
288 | { | ||
289 | struct dchannel *dch = &card->dch; | ||
290 | int count; | ||
291 | u8 *ptr; | ||
292 | u8 cmd = W_D_CMDR_XMS; | ||
293 | |||
294 | pr_debug("%s: fill_Dfifo\n", card->name); | ||
295 | if (!dch->tx_skb) | ||
296 | return; | ||
297 | count = dch->tx_skb->len - dch->tx_idx; | ||
298 | if (count <= 0) | ||
299 | return; | ||
300 | if (count > W_D_FIFO_THRESH) | ||
301 | count = W_D_FIFO_THRESH; | ||
302 | else | ||
303 | cmd |= W_D_CMDR_XME; | ||
304 | ptr = dch->tx_skb->data + dch->tx_idx; | ||
305 | dch->tx_idx += count; | ||
306 | outsb(card->addr + W_D_XFIFO, ptr, count); | ||
307 | WriteW6692(card, W_D_CMDR, cmd); | ||
308 | if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { | ||
309 | pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name); | ||
310 | del_timer(&dch->timer); | ||
311 | } | ||
312 | init_timer(&dch->timer); | ||
313 | dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); | ||
314 | add_timer(&dch->timer); | ||
315 | if (debug & DEBUG_HW_DFIFO) { | ||
316 | snprintf(card->log, 63, "D-send %s %d ", | ||
317 | card->name, count); | ||
318 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | static void | ||
323 | d_retransmit(struct w6692_hw *card) | ||
324 | { | ||
325 | struct dchannel *dch = &card->dch; | ||
326 | |||
327 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
328 | del_timer(&dch->timer); | ||
329 | #ifdef FIXME | ||
330 | if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) | ||
331 | dchannel_sched_event(dch, D_CLEARBUSY); | ||
332 | #endif | ||
333 | if (test_bit(FLG_TX_BUSY, &dch->Flags)) { | ||
334 | /* Restart frame */ | ||
335 | dch->tx_idx = 0; | ||
336 | W6692_fill_Dfifo(card); | ||
337 | } else if (dch->tx_skb) { /* should not happen */ | ||
338 | pr_info("%s: %s without TX_BUSY\n", card->name, __func__); | ||
339 | test_and_set_bit(FLG_TX_BUSY, &dch->Flags); | ||
340 | dch->tx_idx = 0; | ||
341 | W6692_fill_Dfifo(card); | ||
342 | } else { | ||
343 | pr_info("%s: XDU no TX_BUSY\n", card->name); | ||
344 | if (get_next_dframe(dch)) | ||
345 | W6692_fill_Dfifo(card); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | handle_rxD(struct w6692_hw *card) { | ||
351 | u8 stat; | ||
352 | int count; | ||
353 | |||
354 | stat = ReadW6692(card, W_D_RSTA); | ||
355 | if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { | ||
356 | if (stat & W_D_RSTA_RDOV) { | ||
357 | pr_debug("%s: D-channel RDOV\n", card->name); | ||
358 | #ifdef ERROR_STATISTIC | ||
359 | card->dch.err_rx++; | ||
360 | #endif | ||
361 | } | ||
362 | if (stat & W_D_RSTA_CRCE) { | ||
363 | pr_debug("%s: D-channel CRC error\n", card->name); | ||
364 | #ifdef ERROR_STATISTIC | ||
365 | card->dch.err_crc++; | ||
366 | #endif | ||
367 | } | ||
368 | if (stat & W_D_RSTA_RMB) { | ||
369 | pr_debug("%s: D-channel ABORT\n", card->name); | ||
370 | #ifdef ERROR_STATISTIC | ||
371 | card->dch.err_rx++; | ||
372 | #endif | ||
373 | } | ||
374 | if (card->dch.rx_skb) | ||
375 | dev_kfree_skb(card->dch.rx_skb); | ||
376 | card->dch.rx_skb = NULL; | ||
377 | WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); | ||
378 | } else { | ||
379 | count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1); | ||
380 | if (count == 0) | ||
381 | count = W_D_FIFO_THRESH; | ||
382 | W6692_empty_Dfifo(card, count); | ||
383 | recv_Dchannel(&card->dch); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static void | ||
388 | handle_txD(struct w6692_hw *card) { | ||
389 | if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags)) | ||
390 | del_timer(&card->dch.timer); | ||
391 | if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) { | ||
392 | W6692_fill_Dfifo(card); | ||
393 | } else { | ||
394 | if (card->dch.tx_skb) | ||
395 | dev_kfree_skb(card->dch.tx_skb); | ||
396 | if (get_next_dframe(&card->dch)) | ||
397 | W6692_fill_Dfifo(card); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | static void | ||
402 | handle_statusD(struct w6692_hw *card) | ||
403 | { | ||
404 | struct dchannel *dch = &card->dch; | ||
405 | u8 exval, v1, cir; | ||
406 | |||
407 | exval = ReadW6692(card, W_D_EXIR); | ||
408 | |||
409 | pr_debug("%s: D_EXIR %02x\n", card->name, exval); | ||
410 | if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { | ||
411 | /* Transmit underrun/collision */ | ||
412 | pr_debug("%s: D-channel underrun/collision\n", card->name); | ||
413 | #ifdef ERROR_STATISTIC | ||
414 | dch->err_tx++; | ||
415 | #endif | ||
416 | d_retransmit(card); | ||
417 | } | ||
418 | if (exval & W_D_EXI_RDOV) { /* RDOV */ | ||
419 | pr_debug("%s: D-channel RDOV\n", card->name); | ||
420 | WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST); | ||
421 | } | ||
422 | if (exval & W_D_EXI_TIN2) /* TIN2 - never */ | ||
423 | pr_debug("%s: spurious TIN2 interrupt\n", card->name); | ||
424 | if (exval & W_D_EXI_MOC) { /* MOC - not supported */ | ||
425 | v1 = ReadW6692(card, W_MOSR); | ||
426 | pr_debug("%s: spurious MOC interrupt MOSR %02x\n", | ||
427 | card->name, v1); | ||
428 | } | ||
429 | if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ | ||
430 | cir = ReadW6692(card, W_CIR); | ||
431 | pr_debug("%s: ISC CIR %02X\n", card->name, cir); | ||
432 | if (cir & W_CIR_ICC) { | ||
433 | v1 = cir & W_CIR_COD_MASK; | ||
434 | pr_debug("%s: ph_state_change %x -> %x\n", card->name, | ||
435 | dch->state, v1); | ||
436 | card->state = v1; | ||
437 | if (card->fmask & led) { | ||
438 | switch (v1) { | ||
439 | case W_L1IND_AI8: | ||
440 | case W_L1IND_AI10: | ||
441 | w6692_led_handler(card, 1); | ||
442 | break; | ||
443 | default: | ||
444 | w6692_led_handler(card, 0); | ||
445 | break; | ||
446 | } | ||
447 | } | ||
448 | W6692_new_ph(card); | ||
449 | } | ||
450 | if (cir & W_CIR_SCC) { | ||
451 | v1 = ReadW6692(card, W_SQR); | ||
452 | pr_debug("%s: SCC SQR %02X\n", card->name, v1); | ||
453 | } | ||
454 | } | ||
455 | if (exval & W_D_EXI_WEXP) | ||
456 | pr_debug("%s: spurious WEXP interrupt!\n", card->name); | ||
457 | if (exval & W_D_EXI_TEXP) | ||
458 | pr_debug("%s: spurious TEXP interrupt!\n", card->name); | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | W6692_empty_Bfifo(struct w6692_ch *wch, int count) | ||
463 | { | ||
464 | struct w6692_hw *card = wch->bch.hw; | ||
465 | u8 *ptr; | ||
466 | |||
467 | pr_debug("%s: empty_Bfifo %d\n", card->name, count); | ||
468 | if (unlikely(wch->bch.state == ISDN_P_NONE)) { | ||
469 | pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name); | ||
470 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); | ||
471 | if (wch->bch.rx_skb) | ||
472 | skb_trim(wch->bch.rx_skb, 0); | ||
473 | return; | ||
474 | } | ||
475 | if (!wch->bch.rx_skb) { | ||
476 | wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); | ||
477 | if (unlikely(!wch->bch.rx_skb)) { | ||
478 | pr_info("%s: B receive out of memory\n", card->name); | ||
479 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | | ||
480 | W_B_CMDR_RACT); | ||
481 | return; | ||
482 | } | ||
483 | } | ||
484 | if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { | ||
485 | pr_debug("%s: empty_Bfifo incoming packet too large\n", | ||
486 | card->name); | ||
487 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); | ||
488 | skb_trim(wch->bch.rx_skb, 0); | ||
489 | return; | ||
490 | } | ||
491 | ptr = skb_put(wch->bch.rx_skb, count); | ||
492 | insb(wch->addr + W_B_RFIFO, ptr, count); | ||
493 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); | ||
494 | if (debug & DEBUG_HW_DFIFO) { | ||
495 | snprintf(card->log, 63, "B%1d-recv %s %d ", | ||
496 | wch->bch.nr, card->name, count); | ||
497 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | static void | ||
502 | W6692_fill_Bfifo(struct w6692_ch *wch) | ||
503 | { | ||
504 | struct w6692_hw *card = wch->bch.hw; | ||
505 | int count; | ||
506 | u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; | ||
507 | |||
508 | pr_debug("%s: fill Bfifo\n", card->name); | ||
509 | if (!wch->bch.tx_skb) | ||
510 | return; | ||
511 | count = wch->bch.tx_skb->len - wch->bch.tx_idx; | ||
512 | if (count <= 0) | ||
513 | return; | ||
514 | ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; | ||
515 | if (count > W_B_FIFO_THRESH) | ||
516 | count = W_B_FIFO_THRESH; | ||
517 | else if (test_bit(FLG_HDLC, &wch->bch.Flags)) | ||
518 | cmd |= W_B_CMDR_XME; | ||
519 | |||
520 | pr_debug("%s: fill Bfifo%d/%d\n", card->name, | ||
521 | count, wch->bch.tx_idx); | ||
522 | wch->bch.tx_idx += count; | ||
523 | outsb(wch->addr + W_B_XFIFO, ptr, count); | ||
524 | WriteW6692B(wch, W_B_CMDR, cmd); | ||
525 | if (debug & DEBUG_HW_DFIFO) { | ||
526 | snprintf(card->log, 63, "B%1d-send %s %d ", | ||
527 | wch->bch.nr, card->name, count); | ||
528 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | static int | ||
533 | setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) | ||
534 | { | ||
535 | struct w6692_hw *card = wch->bch.hw; | ||
536 | u16 *vol = (u16 *)skb->data; | ||
537 | u8 val; | ||
538 | |||
539 | if ((!(card->fmask & pots)) || | ||
540 | !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) | ||
541 | return -ENODEV; | ||
542 | if (skb->len < 2) | ||
543 | return -EINVAL; | ||
544 | if (*vol > 7) | ||
545 | return -EINVAL; | ||
546 | val = *vol & 7; | ||
547 | val = 7 - val; | ||
548 | if (mic) { | ||
549 | val <<= 3; | ||
550 | card->xaddr &= 0xc7; | ||
551 | } else { | ||
552 | card->xaddr &= 0xf8; | ||
553 | } | ||
554 | card->xaddr |= val; | ||
555 | WriteW6692(card, W_XADDR, card->xaddr); | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int | ||
560 | enable_pots(struct w6692_ch *wch) | ||
561 | { | ||
562 | struct w6692_hw *card = wch->bch.hw; | ||
563 | |||
564 | if ((!(card->fmask & pots)) || | ||
565 | !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) | ||
566 | return -ENODEV; | ||
567 | wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; | ||
568 | WriteW6692B(wch, W_B_MODE, wch->b_mode); | ||
569 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); | ||
570 | card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0); | ||
571 | WriteW6692(card, W_PCTL, card->pctl); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int | ||
576 | disable_pots(struct w6692_ch *wch) | ||
577 | { | ||
578 | struct w6692_hw *card = wch->bch.hw; | ||
579 | |||
580 | if (!(card->fmask & pots)) | ||
581 | return -ENODEV; | ||
582 | wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0); | ||
583 | WriteW6692B(wch, W_B_MODE, wch->b_mode); | ||
584 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | | ||
585 | W_B_CMDR_XRST); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int | ||
590 | w6692_mode(struct w6692_ch *wch, u32 pr) | ||
591 | { | ||
592 | struct w6692_hw *card; | ||
593 | |||
594 | card = wch->bch.hw; | ||
595 | pr_debug("%s: B%d protocol %x-->%x\n", card->name, | ||
596 | wch->bch.nr, wch->bch.state, pr); | ||
597 | switch (pr) { | ||
598 | case ISDN_P_NONE: | ||
599 | if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM)) | ||
600 | disable_pots(wch); | ||
601 | wch->b_mode = 0; | ||
602 | mISDN_clear_bchannel(&wch->bch); | ||
603 | WriteW6692B(wch, W_B_MODE, wch->b_mode); | ||
604 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); | ||
605 | test_and_clear_bit(FLG_HDLC, &wch->bch.Flags); | ||
606 | test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags); | ||
607 | break; | ||
608 | case ISDN_P_B_RAW: | ||
609 | wch->b_mode = W_B_MODE_MMS; | ||
610 | WriteW6692B(wch, W_B_MODE, wch->b_mode); | ||
611 | WriteW6692B(wch, W_B_EXIM, 0); | ||
612 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | | ||
613 | W_B_CMDR_XRST); | ||
614 | test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags); | ||
615 | break; | ||
616 | case ISDN_P_B_HDLC: | ||
617 | wch->b_mode = W_B_MODE_ITF; | ||
618 | WriteW6692B(wch, W_B_MODE, wch->b_mode); | ||
619 | WriteW6692B(wch, W_B_ADM1, 0xff); | ||
620 | WriteW6692B(wch, W_B_ADM2, 0xff); | ||
621 | WriteW6692B(wch, W_B_EXIM, 0); | ||
622 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | | ||
623 | W_B_CMDR_XRST); | ||
624 | test_and_set_bit(FLG_HDLC, &wch->bch.Flags); | ||
625 | break; | ||
626 | default: | ||
627 | pr_info("%s: protocol %x not known\n", card->name, pr); | ||
628 | return -ENOPROTOOPT; | ||
629 | } | ||
630 | wch->bch.state = pr; | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static void | ||
635 | send_next(struct w6692_ch *wch) | ||
636 | { | ||
637 | if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) | ||
638 | W6692_fill_Bfifo(wch); | ||
639 | else { | ||
640 | if (wch->bch.tx_skb) { | ||
641 | /* send confirm, on trans, free on hdlc. */ | ||
642 | if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) | ||
643 | confirm_Bsend(&wch->bch); | ||
644 | dev_kfree_skb(wch->bch.tx_skb); | ||
645 | } | ||
646 | if (get_next_bframe(&wch->bch)) | ||
647 | W6692_fill_Bfifo(wch); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | static void | ||
652 | W6692B_interrupt(struct w6692_hw *card, int ch) | ||
653 | { | ||
654 | struct w6692_ch *wch = &card->bc[ch]; | ||
655 | int count; | ||
656 | u8 stat, star = 0; | ||
657 | |||
658 | stat = ReadW6692B(wch, W_B_EXIR); | ||
659 | pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); | ||
660 | if (stat & W_B_EXI_RME) { | ||
661 | star = ReadW6692B(wch, W_B_STAR); | ||
662 | if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { | ||
663 | if ((star & W_B_STAR_RDOV) && | ||
664 | test_bit(FLG_ACTIVE, &wch->bch.Flags)) { | ||
665 | pr_debug("%s: B%d RDOV proto=%x\n", card->name, | ||
666 | wch->bch.nr, wch->bch.state); | ||
667 | #ifdef ERROR_STATISTIC | ||
668 | wch->bch.err_rdo++; | ||
669 | #endif | ||
670 | } | ||
671 | if (test_bit(FLG_HDLC, &wch->bch.Flags)) { | ||
672 | if (star & W_B_STAR_CRCE) { | ||
673 | pr_debug("%s: B%d CRC error\n", | ||
674 | card->name, wch->bch.nr); | ||
675 | #ifdef ERROR_STATISTIC | ||
676 | wch->bch.err_crc++; | ||
677 | #endif | ||
678 | } | ||
679 | if (star & W_B_STAR_RMB) { | ||
680 | pr_debug("%s: B%d message abort\n", | ||
681 | card->name, wch->bch.nr); | ||
682 | #ifdef ERROR_STATISTIC | ||
683 | wch->bch.err_inv++; | ||
684 | #endif | ||
685 | } | ||
686 | } | ||
687 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | | ||
688 | W_B_CMDR_RRST | W_B_CMDR_RACT); | ||
689 | if (wch->bch.rx_skb) | ||
690 | skb_trim(wch->bch.rx_skb, 0); | ||
691 | } else { | ||
692 | count = ReadW6692B(wch, W_B_RBCL) & | ||
693 | (W_B_FIFO_THRESH - 1); | ||
694 | if (count == 0) | ||
695 | count = W_B_FIFO_THRESH; | ||
696 | W6692_empty_Bfifo(wch, count); | ||
697 | recv_Bchannel(&wch->bch, 0); | ||
698 | } | ||
699 | } | ||
700 | if (stat & W_B_EXI_RMR) { | ||
701 | if (!(stat & W_B_EXI_RME)) | ||
702 | star = ReadW6692B(wch, W_B_STAR); | ||
703 | if (star & W_B_STAR_RDOV) { | ||
704 | pr_debug("%s: B%d RDOV proto=%x\n", card->name, | ||
705 | wch->bch.nr, wch->bch.state); | ||
706 | #ifdef ERROR_STATISTIC | ||
707 | wch->bch.err_rdo++; | ||
708 | #endif | ||
709 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | | ||
710 | W_B_CMDR_RRST | W_B_CMDR_RACT); | ||
711 | } else { | ||
712 | W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); | ||
713 | if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && | ||
714 | wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) | ||
715 | recv_Bchannel(&wch->bch, 0); | ||
716 | } | ||
717 | } | ||
718 | if (stat & W_B_EXI_RDOV) { | ||
719 | /* only if it is not handled yet */ | ||
720 | if (!(star & W_B_STAR_RDOV)) { | ||
721 | pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, | ||
722 | wch->bch.nr, wch->bch.state); | ||
723 | #ifdef ERROR_STATISTIC | ||
724 | wch->bch.err_rdo++; | ||
725 | #endif | ||
726 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | | ||
727 | W_B_CMDR_RRST | W_B_CMDR_RACT); | ||
728 | } | ||
729 | } | ||
730 | if (stat & W_B_EXI_XFR) { | ||
731 | if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { | ||
732 | star = ReadW6692B(wch, W_B_STAR); | ||
733 | pr_debug("%s: B%d star %02x\n", card->name, | ||
734 | wch->bch.nr, star); | ||
735 | } | ||
736 | if (star & W_B_STAR_XDOW) { | ||
737 | pr_debug("%s: B%d XDOW proto=%x\n", card->name, | ||
738 | wch->bch.nr, wch->bch.state); | ||
739 | #ifdef ERROR_STATISTIC | ||
740 | wch->bch.err_xdu++; | ||
741 | #endif | ||
742 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | | ||
743 | W_B_CMDR_RACT); | ||
744 | /* resend */ | ||
745 | if (wch->bch.tx_skb) { | ||
746 | if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) | ||
747 | wch->bch.tx_idx = 0; | ||
748 | } | ||
749 | } | ||
750 | send_next(wch); | ||
751 | if (stat & W_B_EXI_XDUN) | ||
752 | return; /* handle XDOW only once */ | ||
753 | } | ||
754 | if (stat & W_B_EXI_XDUN) { | ||
755 | pr_debug("%s: B%d XDUN proto=%x\n", card->name, | ||
756 | wch->bch.nr, wch->bch.state); | ||
757 | #ifdef ERROR_STATISTIC | ||
758 | wch->bch.err_xdu++; | ||
759 | #endif | ||
760 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); | ||
761 | /* resend */ | ||
762 | if (wch->bch.tx_skb) { | ||
763 | if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) | ||
764 | wch->bch.tx_idx = 0; | ||
765 | } | ||
766 | send_next(wch); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static irqreturn_t | ||
771 | w6692_irq(int intno, void *dev_id) | ||
772 | { | ||
773 | struct w6692_hw *card = dev_id; | ||
774 | u8 ista; | ||
775 | |||
776 | spin_lock(&card->lock); | ||
777 | ista = ReadW6692(card, W_ISTA); | ||
778 | if ((ista | card->imask) == card->imask) { | ||
779 | /* possible a shared IRQ reqest */ | ||
780 | spin_unlock(&card->lock); | ||
781 | return IRQ_NONE; | ||
782 | } | ||
783 | card->irqcnt++; | ||
784 | pr_debug("%s: ista %02x\n", card->name, ista); | ||
785 | ista &= ~card->imask; | ||
786 | if (ista & W_INT_B1_EXI) | ||
787 | W6692B_interrupt(card, 0); | ||
788 | if (ista & W_INT_B2_EXI) | ||
789 | W6692B_interrupt(card, 1); | ||
790 | if (ista & W_INT_D_RME) | ||
791 | handle_rxD(card); | ||
792 | if (ista & W_INT_D_RMR) | ||
793 | W6692_empty_Dfifo(card, W_D_FIFO_THRESH); | ||
794 | if (ista & W_INT_D_XFR) | ||
795 | handle_txD(card); | ||
796 | if (ista & W_INT_D_EXI) | ||
797 | handle_statusD(card); | ||
798 | if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */ | ||
799 | pr_debug("%s: W6692 spurious XINT!\n", card->name); | ||
800 | /* End IRQ Handler */ | ||
801 | spin_unlock(&card->lock); | ||
802 | return IRQ_HANDLED; | ||
803 | } | ||
804 | |||
805 | static void | ||
806 | dbusy_timer_handler(struct dchannel *dch) | ||
807 | { | ||
808 | struct w6692_hw *card = dch->hw; | ||
809 | int rbch, star; | ||
810 | u_long flags; | ||
811 | |||
812 | if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { | ||
813 | spin_lock_irqsave(&card->lock, flags); | ||
814 | rbch = ReadW6692(card, W_D_RBCH); | ||
815 | star = ReadW6692(card, W_D_STAR); | ||
816 | pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", | ||
817 | card->name, rbch, star); | ||
818 | if (star & W_D_STAR_XBZ) /* D-Channel Busy */ | ||
819 | test_and_set_bit(FLG_L1_BUSY, &dch->Flags); | ||
820 | else { | ||
821 | /* discard frame; reset transceiver */ | ||
822 | test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags); | ||
823 | if (dch->tx_idx) | ||
824 | dch->tx_idx = 0; | ||
825 | else | ||
826 | pr_info("%s: W6692 D-Channel Busy no tx_idx\n", | ||
827 | card->name); | ||
828 | /* Transmitter reset */ | ||
829 | WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); | ||
830 | } | ||
831 | spin_unlock_irqrestore(&card->lock, flags); | ||
832 | } | ||
833 | } | ||
834 | |||
835 | void initW6692(struct w6692_hw *card) | ||
836 | { | ||
837 | u8 val; | ||
838 | |||
839 | card->dch.timer.function = (void *)dbusy_timer_handler; | ||
840 | card->dch.timer.data = (u_long)&card->dch; | ||
841 | init_timer(&card->dch.timer); | ||
842 | w6692_mode(&card->bc[0], ISDN_P_NONE); | ||
843 | w6692_mode(&card->bc[1], ISDN_P_NONE); | ||
844 | WriteW6692(card, W_D_CTL, 0x00); | ||
845 | disable_hwirq(card); | ||
846 | WriteW6692(card, W_D_SAM, 0xff); | ||
847 | WriteW6692(card, W_D_TAM, 0xff); | ||
848 | WriteW6692(card, W_D_MODE, W_D_MODE_RACT); | ||
849 | card->state = W_L1CMD_RST; | ||
850 | ph_command(card, W_L1CMD_RST); | ||
851 | ph_command(card, W_L1CMD_ECK); | ||
852 | /* enable all IRQ but extern */ | ||
853 | card->imask = 0x18; | ||
854 | WriteW6692(card, W_D_EXIM, 0x00); | ||
855 | WriteW6692B(&card->bc[0], W_B_EXIM, 0); | ||
856 | WriteW6692B(&card->bc[1], W_B_EXIM, 0); | ||
857 | /* Reset D-chan receiver and transmitter */ | ||
858 | WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); | ||
859 | /* Reset B-chan receiver and transmitter */ | ||
860 | WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); | ||
861 | WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); | ||
862 | /* enable peripheral */ | ||
863 | if (card->subtype == W6692_USR) { | ||
864 | /* seems that USR implemented some power control features | ||
865 | * Pin 79 is connected to the oscilator circuit so we | ||
866 | * have to handle it here | ||
867 | */ | ||
868 | card->pctl = 0x80; | ||
869 | card->xdata = 0; | ||
870 | WriteW6692(card, W_PCTL, card->pctl); | ||
871 | WriteW6692(card, W_XDATA, card->xdata); | ||
872 | } else { | ||
873 | card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | | ||
874 | W_PCTL_OE1 | W_PCTL_OE0; | ||
875 | card->xaddr = 0x00;/* all sw off */ | ||
876 | if (card->fmask & pots) | ||
877 | card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */ | ||
878 | if (card->fmask & led) | ||
879 | card->xdata |= 0x04; /* LED OFF */ | ||
880 | if ((card->fmask & pots) || (card->fmask & led)) { | ||
881 | WriteW6692(card, W_PCTL, card->pctl); | ||
882 | WriteW6692(card, W_XADDR, card->xaddr); | ||
883 | WriteW6692(card, W_XDATA, card->xdata); | ||
884 | val = ReadW6692(card, W_XADDR); | ||
885 | if (debug & DEBUG_HW) | ||
886 | pr_notice("%s: W_XADDR=%02x\n", | ||
887 | card->name, val); | ||
888 | } | ||
889 | } | ||
890 | } | ||
891 | |||
892 | static void | ||
893 | reset_w6692(struct w6692_hw *card) | ||
894 | { | ||
895 | WriteW6692(card, W_D_CTL, W_D_CTL_SRST); | ||
896 | mdelay(10); | ||
897 | WriteW6692(card, W_D_CTL, 0); | ||
898 | } | ||
899 | |||
900 | static int | ||
901 | init_card(struct w6692_hw *card) | ||
902 | { | ||
903 | int cnt = 3; | ||
904 | u_long flags; | ||
905 | |||
906 | spin_lock_irqsave(&card->lock, flags); | ||
907 | disable_hwirq(card); | ||
908 | spin_unlock_irqrestore(&card->lock, flags); | ||
909 | if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) { | ||
910 | pr_info("%s: couldn't get interrupt %d\n", card->name, | ||
911 | card->irq); | ||
912 | return -EIO; | ||
913 | } | ||
914 | while (cnt--) { | ||
915 | spin_lock_irqsave(&card->lock, flags); | ||
916 | initW6692(card); | ||
917 | enable_hwirq(card); | ||
918 | spin_unlock_irqrestore(&card->lock, flags); | ||
919 | /* Timeout 10ms */ | ||
920 | msleep_interruptible(10); | ||
921 | if (debug & DEBUG_HW) | ||
922 | pr_notice("%s: IRQ %d count %d\n", card->name, | ||
923 | card->irq, card->irqcnt); | ||
924 | if (!card->irqcnt) { | ||
925 | pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", | ||
926 | card->name, card->irq, 3 - cnt); | ||
927 | reset_w6692(card); | ||
928 | } else | ||
929 | return 0; | ||
930 | } | ||
931 | free_irq(card->irq, card); | ||
932 | return -EIO; | ||
933 | } | ||
934 | |||
935 | static int | ||
936 | w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) | ||
937 | { | ||
938 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
939 | struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); | ||
940 | struct w6692_hw *card = bch->hw; | ||
941 | int ret = -EINVAL; | ||
942 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
943 | u32 id; | ||
944 | u_long flags; | ||
945 | |||
946 | switch (hh->prim) { | ||
947 | case PH_DATA_REQ: | ||
948 | spin_lock_irqsave(&card->lock, flags); | ||
949 | ret = bchannel_senddata(bch, skb); | ||
950 | if (ret > 0) { /* direct TX */ | ||
951 | id = hh->id; /* skb can be freed */ | ||
952 | ret = 0; | ||
953 | W6692_fill_Bfifo(bc); | ||
954 | spin_unlock_irqrestore(&card->lock, flags); | ||
955 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
956 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
957 | } else | ||
958 | spin_unlock_irqrestore(&card->lock, flags); | ||
959 | return ret; | ||
960 | case PH_ACTIVATE_REQ: | ||
961 | spin_lock_irqsave(&card->lock, flags); | ||
962 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
963 | ret = w6692_mode(bc, ch->protocol); | ||
964 | else | ||
965 | ret = 0; | ||
966 | spin_unlock_irqrestore(&card->lock, flags); | ||
967 | if (!ret) | ||
968 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
969 | NULL, GFP_KERNEL); | ||
970 | break; | ||
971 | case PH_DEACTIVATE_REQ: | ||
972 | spin_lock_irqsave(&card->lock, flags); | ||
973 | mISDN_clear_bchannel(bch); | ||
974 | w6692_mode(bc, ISDN_P_NONE); | ||
975 | spin_unlock_irqrestore(&card->lock, flags); | ||
976 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
977 | NULL, GFP_KERNEL); | ||
978 | ret = 0; | ||
979 | break; | ||
980 | default: | ||
981 | pr_info("%s: %s unknown prim(%x,%x)\n", | ||
982 | card->name, __func__, hh->prim, hh->id); | ||
983 | ret = -EINVAL; | ||
984 | } | ||
985 | if (!ret) | ||
986 | dev_kfree_skb(skb); | ||
987 | return ret; | ||
988 | } | ||
989 | |||
990 | static int | ||
991 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
992 | { | ||
993 | int ret = 0; | ||
994 | |||
995 | switch (cq->op) { | ||
996 | case MISDN_CTRL_GETOP: | ||
997 | cq->op = 0; | ||
998 | break; | ||
999 | /* Nothing implemented yet */ | ||
1000 | case MISDN_CTRL_FILL_EMPTY: | ||
1001 | default: | ||
1002 | pr_info("%s: unknown Op %x\n", __func__, cq->op); | ||
1003 | ret = -EINVAL; | ||
1004 | break; | ||
1005 | } | ||
1006 | return ret; | ||
1007 | } | ||
1008 | |||
1009 | static int | ||
1010 | open_bchannel(struct w6692_hw *card, struct channel_req *rq) | ||
1011 | { | ||
1012 | struct bchannel *bch; | ||
1013 | |||
1014 | if (rq->adr.channel > 2) | ||
1015 | return -EINVAL; | ||
1016 | if (rq->protocol == ISDN_P_NONE) | ||
1017 | return -EINVAL; | ||
1018 | bch = &card->bc[rq->adr.channel - 1].bch; | ||
1019 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
1020 | return -EBUSY; /* b-channel can be only open once */ | ||
1021 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | ||
1022 | bch->ch.protocol = rq->protocol; | ||
1023 | rq->ch = &bch->ch; | ||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static int | ||
1028 | channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq) | ||
1029 | { | ||
1030 | int ret = 0; | ||
1031 | |||
1032 | switch (cq->op) { | ||
1033 | case MISDN_CTRL_GETOP: | ||
1034 | cq->op = 0; | ||
1035 | break; | ||
1036 | default: | ||
1037 | pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op); | ||
1038 | ret = -EINVAL; | ||
1039 | break; | ||
1040 | } | ||
1041 | return ret; | ||
1042 | } | ||
1043 | |||
1044 | static int | ||
1045 | w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
1046 | { | ||
1047 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1048 | struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); | ||
1049 | struct w6692_hw *card = bch->hw; | ||
1050 | int ret = -EINVAL; | ||
1051 | u_long flags; | ||
1052 | |||
1053 | pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); | ||
1054 | switch (cmd) { | ||
1055 | case CLOSE_CHANNEL: | ||
1056 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
1057 | if (test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
1058 | spin_lock_irqsave(&card->lock, flags); | ||
1059 | mISDN_freebchannel(bch); | ||
1060 | w6692_mode(bc, ISDN_P_NONE); | ||
1061 | spin_unlock_irqrestore(&card->lock, flags); | ||
1062 | } else { | ||
1063 | skb_queue_purge(&bch->rqueue); | ||
1064 | bch->rcount = 0; | ||
1065 | } | ||
1066 | ch->protocol = ISDN_P_NONE; | ||
1067 | ch->peer = NULL; | ||
1068 | module_put(THIS_MODULE); | ||
1069 | ret = 0; | ||
1070 | break; | ||
1071 | case CONTROL_CHANNEL: | ||
1072 | ret = channel_bctrl(bch, arg); | ||
1073 | break; | ||
1074 | default: | ||
1075 | pr_info("%s: %s unknown prim(%x)\n", | ||
1076 | card->name, __func__, cmd); | ||
1077 | } | ||
1078 | return ret; | ||
1079 | } | ||
1080 | |||
1081 | static int | ||
1082 | w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1083 | { | ||
1084 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1085 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1086 | struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); | ||
1087 | int ret = -EINVAL; | ||
1088 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1089 | u32 id; | ||
1090 | u_long flags; | ||
1091 | |||
1092 | switch (hh->prim) { | ||
1093 | case PH_DATA_REQ: | ||
1094 | spin_lock_irqsave(&card->lock, flags); | ||
1095 | ret = dchannel_senddata(dch, skb); | ||
1096 | if (ret > 0) { /* direct TX */ | ||
1097 | id = hh->id; /* skb can be freed */ | ||
1098 | W6692_fill_Dfifo(card); | ||
1099 | ret = 0; | ||
1100 | spin_unlock_irqrestore(&card->lock, flags); | ||
1101 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
1102 | } else | ||
1103 | spin_unlock_irqrestore(&card->lock, flags); | ||
1104 | return ret; | ||
1105 | case PH_ACTIVATE_REQ: | ||
1106 | ret = l1_event(dch->l1, hh->prim); | ||
1107 | break; | ||
1108 | case PH_DEACTIVATE_REQ: | ||
1109 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
1110 | ret = l1_event(dch->l1, hh->prim); | ||
1111 | break; | ||
1112 | } | ||
1113 | |||
1114 | if (!ret) | ||
1115 | dev_kfree_skb(skb); | ||
1116 | return ret; | ||
1117 | } | ||
1118 | |||
1119 | static int | ||
1120 | w6692_l1callback(struct dchannel *dch, u32 cmd) | ||
1121 | { | ||
1122 | struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); | ||
1123 | u_long flags; | ||
1124 | |||
1125 | pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state); | ||
1126 | switch (cmd) { | ||
1127 | case INFO3_P8: | ||
1128 | spin_lock_irqsave(&card->lock, flags); | ||
1129 | ph_command(card, W_L1CMD_AR8); | ||
1130 | spin_unlock_irqrestore(&card->lock, flags); | ||
1131 | break; | ||
1132 | case INFO3_P10: | ||
1133 | spin_lock_irqsave(&card->lock, flags); | ||
1134 | ph_command(card, W_L1CMD_AR10); | ||
1135 | spin_unlock_irqrestore(&card->lock, flags); | ||
1136 | break; | ||
1137 | case HW_RESET_REQ: | ||
1138 | spin_lock_irqsave(&card->lock, flags); | ||
1139 | if (card->state != W_L1IND_DRD) | ||
1140 | ph_command(card, W_L1CMD_RST); | ||
1141 | ph_command(card, W_L1CMD_ECK); | ||
1142 | spin_unlock_irqrestore(&card->lock, flags); | ||
1143 | break; | ||
1144 | case HW_DEACT_REQ: | ||
1145 | skb_queue_purge(&dch->squeue); | ||
1146 | if (dch->tx_skb) { | ||
1147 | dev_kfree_skb(dch->tx_skb); | ||
1148 | dch->tx_skb = NULL; | ||
1149 | } | ||
1150 | dch->tx_idx = 0; | ||
1151 | if (dch->rx_skb) { | ||
1152 | dev_kfree_skb(dch->rx_skb); | ||
1153 | dch->rx_skb = NULL; | ||
1154 | } | ||
1155 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
1156 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
1157 | del_timer(&dch->timer); | ||
1158 | break; | ||
1159 | case HW_POWERUP_REQ: | ||
1160 | spin_lock_irqsave(&card->lock, flags); | ||
1161 | ph_command(card, W_L1CMD_ECK); | ||
1162 | spin_unlock_irqrestore(&card->lock, flags); | ||
1163 | break; | ||
1164 | case PH_ACTIVATE_IND: | ||
1165 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
1166 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
1167 | GFP_ATOMIC); | ||
1168 | break; | ||
1169 | case PH_DEACTIVATE_IND: | ||
1170 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
1171 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
1172 | GFP_ATOMIC); | ||
1173 | break; | ||
1174 | default: | ||
1175 | pr_debug("%s: %s unknown command %x\n", card->name, | ||
1176 | __func__, cmd); | ||
1177 | return -1; | ||
1178 | } | ||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | static int | ||
1183 | open_dchannel(struct w6692_hw *card, struct channel_req *rq) | ||
1184 | { | ||
1185 | pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__, | ||
1186 | card->dch.dev.id, __builtin_return_address(1)); | ||
1187 | if (rq->protocol != ISDN_P_TE_S0) | ||
1188 | return -EINVAL; | ||
1189 | if (rq->adr.channel == 1) | ||
1190 | /* E-Channel not supported */ | ||
1191 | return -EINVAL; | ||
1192 | rq->ch = &card->dch.dev.D; | ||
1193 | rq->ch->protocol = rq->protocol; | ||
1194 | if (card->dch.state == 7) | ||
1195 | _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
1196 | 0, NULL, GFP_KERNEL); | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static int | ||
1201 | w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) | ||
1202 | { | ||
1203 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1204 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1205 | struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); | ||
1206 | struct channel_req *rq; | ||
1207 | int err = 0; | ||
1208 | |||
1209 | pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg); | ||
1210 | switch (cmd) { | ||
1211 | case OPEN_CHANNEL: | ||
1212 | rq = arg; | ||
1213 | if (rq->protocol == ISDN_P_TE_S0) | ||
1214 | err = open_dchannel(card, rq); | ||
1215 | else | ||
1216 | err = open_bchannel(card, rq); | ||
1217 | if (err) | ||
1218 | break; | ||
1219 | if (!try_module_get(THIS_MODULE)) | ||
1220 | pr_info("%s: cannot get module\n", card->name); | ||
1221 | break; | ||
1222 | case CLOSE_CHANNEL: | ||
1223 | pr_debug("%s: dev(%d) close from %p\n", card->name, | ||
1224 | dch->dev.id, __builtin_return_address(0)); | ||
1225 | module_put(THIS_MODULE); | ||
1226 | break; | ||
1227 | case CONTROL_CHANNEL: | ||
1228 | err = channel_ctrl(card, arg); | ||
1229 | break; | ||
1230 | default: | ||
1231 | pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd); | ||
1232 | return -EINVAL; | ||
1233 | } | ||
1234 | return err; | ||
1235 | } | ||
1236 | |||
1237 | static int | ||
1238 | setup_w6692(struct w6692_hw *card) | ||
1239 | { | ||
1240 | u32 val; | ||
1241 | |||
1242 | if (!request_region(card->addr, 256, card->name)) { | ||
1243 | pr_info("%s: config port %x-%x already in use\n", card->name, | ||
1244 | card->addr, card->addr + 255); | ||
1245 | return -EIO; | ||
1246 | } | ||
1247 | W6692Version(card); | ||
1248 | card->bc[0].addr = card->addr; | ||
1249 | card->bc[1].addr = card->addr + 0x40; | ||
1250 | val = ReadW6692(card, W_ISTA); | ||
1251 | if (debug & DEBUG_HW) | ||
1252 | pr_notice("%s ISTA=%02x\n", card->name, val); | ||
1253 | val = ReadW6692(card, W_IMASK); | ||
1254 | if (debug & DEBUG_HW) | ||
1255 | pr_notice("%s IMASK=%02x\n", card->name, val); | ||
1256 | val = ReadW6692(card, W_D_EXIR); | ||
1257 | if (debug & DEBUG_HW) | ||
1258 | pr_notice("%s D_EXIR=%02x\n", card->name, val); | ||
1259 | val = ReadW6692(card, W_D_EXIM); | ||
1260 | if (debug & DEBUG_HW) | ||
1261 | pr_notice("%s D_EXIM=%02x\n", card->name, val); | ||
1262 | val = ReadW6692(card, W_D_RSTA); | ||
1263 | if (debug & DEBUG_HW) | ||
1264 | pr_notice("%s D_RSTA=%02x\n", card->name, val); | ||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1268 | static void | ||
1269 | release_card(struct w6692_hw *card) | ||
1270 | { | ||
1271 | u_long flags; | ||
1272 | |||
1273 | spin_lock_irqsave(&card->lock, flags); | ||
1274 | disable_hwirq(card); | ||
1275 | w6692_mode(&card->bc[0], ISDN_P_NONE); | ||
1276 | w6692_mode(&card->bc[1], ISDN_P_NONE); | ||
1277 | if ((card->fmask & led) || card->subtype == W6692_USR) { | ||
1278 | card->xdata |= 0x04; /* LED OFF */ | ||
1279 | WriteW6692(card, W_XDATA, card->xdata); | ||
1280 | } | ||
1281 | spin_unlock_irqrestore(&card->lock, flags); | ||
1282 | free_irq(card->irq, card); | ||
1283 | l1_event(card->dch.l1, CLOSE_CHANNEL); | ||
1284 | mISDN_unregister_device(&card->dch.dev); | ||
1285 | release_region(card->addr, 256); | ||
1286 | mISDN_freebchannel(&card->bc[1].bch); | ||
1287 | mISDN_freebchannel(&card->bc[0].bch); | ||
1288 | mISDN_freedchannel(&card->dch); | ||
1289 | write_lock_irqsave(&card_lock, flags); | ||
1290 | list_del(&card->list); | ||
1291 | write_unlock_irqrestore(&card_lock, flags); | ||
1292 | pci_disable_device(card->pdev); | ||
1293 | pci_set_drvdata(card->pdev, NULL); | ||
1294 | kfree(card); | ||
1295 | } | ||
1296 | |||
1297 | static int | ||
1298 | setup_instance(struct w6692_hw *card) | ||
1299 | { | ||
1300 | int i, err; | ||
1301 | u_long flags; | ||
1302 | |||
1303 | snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1); | ||
1304 | write_lock_irqsave(&card_lock, flags); | ||
1305 | list_add_tail(&card->list, &Cards); | ||
1306 | write_unlock_irqrestore(&card_lock, flags); | ||
1307 | card->fmask = (1 << w6692_cnt); | ||
1308 | _set_debug(card); | ||
1309 | spin_lock_init(&card->lock); | ||
1310 | mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh); | ||
1311 | card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); | ||
1312 | card->dch.dev.D.send = w6692_l2l1D; | ||
1313 | card->dch.dev.D.ctrl = w6692_dctrl; | ||
1314 | card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1315 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
1316 | card->dch.hw = card; | ||
1317 | card->dch.dev.nrbchan = 2; | ||
1318 | for (i = 0; i < 2; i++) { | ||
1319 | mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); | ||
1320 | card->bc[i].bch.hw = card; | ||
1321 | card->bc[i].bch.nr = i + 1; | ||
1322 | card->bc[i].bch.ch.nr = i + 1; | ||
1323 | card->bc[i].bch.ch.send = w6692_l2l1B; | ||
1324 | card->bc[i].bch.ch.ctrl = w6692_bctrl; | ||
1325 | set_channelmap(i + 1, card->dch.dev.channelmap); | ||
1326 | list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels); | ||
1327 | } | ||
1328 | err = setup_w6692(card); | ||
1329 | if (err) | ||
1330 | goto error_setup; | ||
1331 | err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, | ||
1332 | card->name); | ||
1333 | if (err) | ||
1334 | goto error_reg; | ||
1335 | err = init_card(card); | ||
1336 | if (err) | ||
1337 | goto error_init; | ||
1338 | err = create_l1(&card->dch, w6692_l1callback); | ||
1339 | if (!err) { | ||
1340 | w6692_cnt++; | ||
1341 | pr_notice("W6692 %d cards installed\n", w6692_cnt); | ||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | free_irq(card->irq, card); | ||
1346 | error_init: | ||
1347 | mISDN_unregister_device(&card->dch.dev); | ||
1348 | error_reg: | ||
1349 | release_region(card->addr, 256); | ||
1350 | error_setup: | ||
1351 | mISDN_freebchannel(&card->bc[1].bch); | ||
1352 | mISDN_freebchannel(&card->bc[0].bch); | ||
1353 | mISDN_freedchannel(&card->dch); | ||
1354 | write_lock_irqsave(&card_lock, flags); | ||
1355 | list_del(&card->list); | ||
1356 | write_unlock_irqrestore(&card_lock, flags); | ||
1357 | kfree(card); | ||
1358 | return err; | ||
1359 | } | ||
1360 | |||
1361 | static int __devinit | ||
1362 | w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
1363 | { | ||
1364 | int err = -ENOMEM; | ||
1365 | struct w6692_hw *card; | ||
1366 | struct w6692map *m = (struct w6692map *)ent->driver_data; | ||
1367 | |||
1368 | card = kzalloc(sizeof(struct w6692_hw), GFP_KERNEL); | ||
1369 | if (!card) { | ||
1370 | pr_info("No kmem for w6692 card\n"); | ||
1371 | return err; | ||
1372 | } | ||
1373 | card->pdev = pdev; | ||
1374 | card->subtype = m->subtype; | ||
1375 | err = pci_enable_device(pdev); | ||
1376 | if (err) { | ||
1377 | kfree(card); | ||
1378 | return err; | ||
1379 | } | ||
1380 | |||
1381 | printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", | ||
1382 | m->name, pci_name(pdev)); | ||
1383 | |||
1384 | card->addr = pci_resource_start(pdev, 1); | ||
1385 | card->irq = pdev->irq; | ||
1386 | pci_set_drvdata(pdev, card); | ||
1387 | err = setup_instance(card); | ||
1388 | if (err) | ||
1389 | pci_set_drvdata(pdev, NULL); | ||
1390 | return err; | ||
1391 | } | ||
1392 | |||
1393 | static void __devexit | ||
1394 | w6692_remove_pci(struct pci_dev *pdev) | ||
1395 | { | ||
1396 | struct w6692_hw *card = pci_get_drvdata(pdev); | ||
1397 | |||
1398 | if (card) | ||
1399 | release_card(card); | ||
1400 | else | ||
1401 | if (debug) | ||
1402 | pr_notice("%s: drvdata allready removed\n", __func__); | ||
1403 | } | ||
1404 | |||
1405 | static struct pci_device_id w6692_ids[] = { | ||
1406 | { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, | ||
1407 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]}, | ||
1408 | { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, | ||
1409 | PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0, | ||
1410 | (ulong)&w6692_map[2]}, | ||
1411 | { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, | ||
1412 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]}, | ||
1413 | { } | ||
1414 | }; | ||
1415 | MODULE_DEVICE_TABLE(pci, w6692_ids); | ||
1416 | |||
1417 | static struct pci_driver w6692_driver = { | ||
1418 | .name = "w6692", | ||
1419 | .probe = w6692_probe, | ||
1420 | .remove = __devexit_p(w6692_remove_pci), | ||
1421 | .id_table = w6692_ids, | ||
1422 | }; | ||
1423 | |||
1424 | static int __init w6692_init(void) | ||
1425 | { | ||
1426 | int err; | ||
1427 | |||
1428 | pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV); | ||
1429 | |||
1430 | err = pci_register_driver(&w6692_driver); | ||
1431 | return err; | ||
1432 | } | ||
1433 | |||
1434 | static void __exit w6692_cleanup(void) | ||
1435 | { | ||
1436 | pci_unregister_driver(&w6692_driver); | ||
1437 | } | ||
1438 | |||
1439 | module_init(w6692_init); | ||
1440 | module_exit(w6692_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h new file mode 100644 index 000000000000..f95697757fd0 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/w6692.h | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Winbond W6692 specific defines | ||
3 | * | ||
4 | * Author Karsten Keil <keil@isdn4linux.de> | ||
5 | * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz> | ||
6 | * | ||
7 | * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* Specifications of W6692 registers */ | ||
25 | |||
26 | #define W_D_RFIFO 0x00 /* R */ | ||
27 | #define W_D_XFIFO 0x04 /* W */ | ||
28 | #define W_D_CMDR 0x08 /* W */ | ||
29 | #define W_D_MODE 0x0c /* R/W */ | ||
30 | #define W_D_TIMR 0x10 /* R/W */ | ||
31 | #define W_ISTA 0x14 /* R_clr */ | ||
32 | #define W_IMASK 0x18 /* R/W */ | ||
33 | #define W_D_EXIR 0x1c /* R_clr */ | ||
34 | #define W_D_EXIM 0x20 /* R/W */ | ||
35 | #define W_D_STAR 0x24 /* R */ | ||
36 | #define W_D_RSTA 0x28 /* R */ | ||
37 | #define W_D_SAM 0x2c /* R/W */ | ||
38 | #define W_D_SAP1 0x30 /* R/W */ | ||
39 | #define W_D_SAP2 0x34 /* R/W */ | ||
40 | #define W_D_TAM 0x38 /* R/W */ | ||
41 | #define W_D_TEI1 0x3c /* R/W */ | ||
42 | #define W_D_TEI2 0x40 /* R/W */ | ||
43 | #define W_D_RBCH 0x44 /* R */ | ||
44 | #define W_D_RBCL 0x48 /* R */ | ||
45 | #define W_TIMR2 0x4c /* W */ | ||
46 | #define W_L1_RC 0x50 /* R/W */ | ||
47 | #define W_D_CTL 0x54 /* R/W */ | ||
48 | #define W_CIR 0x58 /* R */ | ||
49 | #define W_CIX 0x5c /* W */ | ||
50 | #define W_SQR 0x60 /* R */ | ||
51 | #define W_SQX 0x64 /* W */ | ||
52 | #define W_PCTL 0x68 /* R/W */ | ||
53 | #define W_MOR 0x6c /* R */ | ||
54 | #define W_MOX 0x70 /* R/W */ | ||
55 | #define W_MOSR 0x74 /* R_clr */ | ||
56 | #define W_MOCR 0x78 /* R/W */ | ||
57 | #define W_GCR 0x7c /* R/W */ | ||
58 | |||
59 | #define W_B_RFIFO 0x80 /* R */ | ||
60 | #define W_B_XFIFO 0x84 /* W */ | ||
61 | #define W_B_CMDR 0x88 /* W */ | ||
62 | #define W_B_MODE 0x8c /* R/W */ | ||
63 | #define W_B_EXIR 0x90 /* R_clr */ | ||
64 | #define W_B_EXIM 0x94 /* R/W */ | ||
65 | #define W_B_STAR 0x98 /* R */ | ||
66 | #define W_B_ADM1 0x9c /* R/W */ | ||
67 | #define W_B_ADM2 0xa0 /* R/W */ | ||
68 | #define W_B_ADR1 0xa4 /* R/W */ | ||
69 | #define W_B_ADR2 0xa8 /* R/W */ | ||
70 | #define W_B_RBCL 0xac /* R */ | ||
71 | #define W_B_RBCH 0xb0 /* R */ | ||
72 | |||
73 | #define W_XADDR 0xf4 /* R/W */ | ||
74 | #define W_XDATA 0xf8 /* R/W */ | ||
75 | #define W_EPCTL 0xfc /* W */ | ||
76 | |||
77 | /* W6692 register bits */ | ||
78 | |||
79 | #define W_D_CMDR_XRST 0x01 | ||
80 | #define W_D_CMDR_XME 0x02 | ||
81 | #define W_D_CMDR_XMS 0x08 | ||
82 | #define W_D_CMDR_STT 0x10 | ||
83 | #define W_D_CMDR_RRST 0x40 | ||
84 | #define W_D_CMDR_RACK 0x80 | ||
85 | |||
86 | #define W_D_MODE_RLP 0x01 | ||
87 | #define W_D_MODE_DLP 0x02 | ||
88 | #define W_D_MODE_MFD 0x04 | ||
89 | #define W_D_MODE_TEE 0x08 | ||
90 | #define W_D_MODE_TMS 0x10 | ||
91 | #define W_D_MODE_RACT 0x40 | ||
92 | #define W_D_MODE_MMS 0x80 | ||
93 | |||
94 | #define W_INT_B2_EXI 0x01 | ||
95 | #define W_INT_B1_EXI 0x02 | ||
96 | #define W_INT_D_EXI 0x04 | ||
97 | #define W_INT_XINT0 0x08 | ||
98 | #define W_INT_XINT1 0x10 | ||
99 | #define W_INT_D_XFR 0x20 | ||
100 | #define W_INT_D_RME 0x40 | ||
101 | #define W_INT_D_RMR 0x80 | ||
102 | |||
103 | #define W_D_EXI_WEXP 0x01 | ||
104 | #define W_D_EXI_TEXP 0x02 | ||
105 | #define W_D_EXI_ISC 0x04 | ||
106 | #define W_D_EXI_MOC 0x08 | ||
107 | #define W_D_EXI_TIN2 0x10 | ||
108 | #define W_D_EXI_XCOL 0x20 | ||
109 | #define W_D_EXI_XDUN 0x40 | ||
110 | #define W_D_EXI_RDOV 0x80 | ||
111 | |||
112 | #define W_D_STAR_DRDY 0x10 | ||
113 | #define W_D_STAR_XBZ 0x20 | ||
114 | #define W_D_STAR_XDOW 0x80 | ||
115 | |||
116 | #define W_D_RSTA_RMB 0x10 | ||
117 | #define W_D_RSTA_CRCE 0x20 | ||
118 | #define W_D_RSTA_RDOV 0x40 | ||
119 | |||
120 | #define W_D_CTL_SRST 0x20 | ||
121 | |||
122 | #define W_CIR_SCC 0x80 | ||
123 | #define W_CIR_ICC 0x40 | ||
124 | #define W_CIR_COD_MASK 0x0f | ||
125 | |||
126 | #define W_PCTL_PCX 0x01 | ||
127 | #define W_PCTL_XMODE 0x02 | ||
128 | #define W_PCTL_OE0 0x04 | ||
129 | #define W_PCTL_OE1 0x08 | ||
130 | #define W_PCTL_OE2 0x10 | ||
131 | #define W_PCTL_OE3 0x20 | ||
132 | #define W_PCTL_OE4 0x40 | ||
133 | #define W_PCTL_OE5 0x80 | ||
134 | |||
135 | #define W_B_CMDR_XRST 0x01 | ||
136 | #define W_B_CMDR_XME 0x02 | ||
137 | #define W_B_CMDR_XMS 0x04 | ||
138 | #define W_B_CMDR_RACT 0x20 | ||
139 | #define W_B_CMDR_RRST 0x40 | ||
140 | #define W_B_CMDR_RACK 0x80 | ||
141 | |||
142 | #define W_B_MODE_FTS0 0x01 | ||
143 | #define W_B_MODE_FTS1 0x02 | ||
144 | #define W_B_MODE_SW56 0x04 | ||
145 | #define W_B_MODE_BSW0 0x08 | ||
146 | #define W_B_MODE_BSW1 0x10 | ||
147 | #define W_B_MODE_EPCM 0x20 | ||
148 | #define W_B_MODE_ITF 0x40 | ||
149 | #define W_B_MODE_MMS 0x80 | ||
150 | |||
151 | #define W_B_EXI_XDUN 0x01 | ||
152 | #define W_B_EXI_XFR 0x02 | ||
153 | #define W_B_EXI_RDOV 0x10 | ||
154 | #define W_B_EXI_RME 0x20 | ||
155 | #define W_B_EXI_RMR 0x40 | ||
156 | |||
157 | #define W_B_STAR_XBZ 0x01 | ||
158 | #define W_B_STAR_XDOW 0x04 | ||
159 | #define W_B_STAR_RMB 0x10 | ||
160 | #define W_B_STAR_CRCE 0x20 | ||
161 | #define W_B_STAR_RDOV 0x40 | ||
162 | |||
163 | #define W_B_RBCH_LOV 0x20 | ||
164 | |||
165 | /* W6692 Layer1 commands */ | ||
166 | |||
167 | #define W_L1CMD_ECK 0x00 | ||
168 | #define W_L1CMD_RST 0x01 | ||
169 | #define W_L1CMD_SCP 0x04 | ||
170 | #define W_L1CMD_SSP 0x02 | ||
171 | #define W_L1CMD_AR8 0x08 | ||
172 | #define W_L1CMD_AR10 0x09 | ||
173 | #define W_L1CMD_EAL 0x0a | ||
174 | #define W_L1CMD_DRC 0x0f | ||
175 | |||
176 | /* W6692 Layer1 indications */ | ||
177 | |||
178 | #define W_L1IND_CE 0x07 | ||
179 | #define W_L1IND_DRD 0x00 | ||
180 | #define W_L1IND_LD 0x04 | ||
181 | #define W_L1IND_ARD 0x08 | ||
182 | #define W_L1IND_TI 0x0a | ||
183 | #define W_L1IND_ATI 0x0b | ||
184 | #define W_L1IND_AI8 0x0c | ||
185 | #define W_L1IND_AI10 0x0d | ||
186 | #define W_L1IND_CD 0x0f | ||
187 | |||
188 | /* FIFO thresholds */ | ||
189 | #define W_D_FIFO_THRESH 64 | ||
190 | #define W_B_FIFO_THRESH 64 | ||
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index 7832d8ba8e44..3464ebc4cdbc 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig | |||
@@ -391,6 +391,7 @@ comment "HiSax sub driver modules" | |||
391 | config HISAX_ST5481 | 391 | config HISAX_ST5481 |
392 | tristate "ST5481 USB ISDN modem (EXPERIMENTAL)" | 392 | tristate "ST5481 USB ISDN modem (EXPERIMENTAL)" |
393 | depends on USB && EXPERIMENTAL | 393 | depends on USB && EXPERIMENTAL |
394 | select ISDN_HDLC | ||
394 | select CRC_CCITT | 395 | select CRC_CCITT |
395 | select BITREVERSE | 396 | select BITREVERSE |
396 | help | 397 | help |
@@ -418,11 +419,6 @@ config HISAX_FRITZ_PCIPNP | |||
418 | (the latter also needs you to select "ISA Plug and Play support" | 419 | (the latter also needs you to select "ISA Plug and Play support" |
419 | from the menu "Plug and Play configuration") | 420 | from the menu "Plug and Play configuration") |
420 | 421 | ||
421 | config HISAX_HDLC | ||
422 | bool | ||
423 | depends on HISAX_ST5481 | ||
424 | default y | ||
425 | |||
426 | config HISAX_AVM_A1_PCMCIA | 422 | config HISAX_AVM_A1_PCMCIA |
427 | bool | 423 | bool |
428 | depends on HISAX_AVM_A1_CS | 424 | depends on HISAX_AVM_A1_CS |
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index c7a3794bdae4..ab638b083df9 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile | |||
@@ -16,10 +16,6 @@ obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o | |||
16 | obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o | 16 | obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o |
17 | obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o | 17 | obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o |
18 | 18 | ||
19 | ifdef CONFIG_HISAX_HDLC | ||
20 | obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o | ||
21 | endif | ||
22 | |||
23 | # Multipart objects. | 19 | # Multipart objects. |
24 | 20 | ||
25 | hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ | 21 | hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ |
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index 341faf58a65c..bf526a7a63af 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c | |||
@@ -238,8 +238,6 @@ Amd7930_bh(struct work_struct *work) | |||
238 | container_of(work, struct IsdnCardState, tqueue); | 238 | container_of(work, struct IsdnCardState, tqueue); |
239 | struct PStack *stptr; | 239 | struct PStack *stptr; |
240 | 240 | ||
241 | if (!cs) | ||
242 | return; | ||
243 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { | 241 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { |
244 | if (cs->debug) | 242 | if (cs->debug) |
245 | debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); | 243 | debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); |
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 025a20d487c5..475b1a020003 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c | |||
@@ -833,8 +833,6 @@ static struct FsmNode fnlist[] __initdata = | |||
833 | }; | 833 | }; |
834 | /* *INDENT-ON* */ | 834 | /* *INDENT-ON* */ |
835 | 835 | ||
836 | #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) | ||
837 | |||
838 | int __init | 836 | int __init |
839 | CallcNew(void) | 837 | CallcNew(void) |
840 | { | 838 | { |
@@ -842,7 +840,7 @@ CallcNew(void) | |||
842 | callcfsm.event_count = EVENT_COUNT; | 840 | callcfsm.event_count = EVENT_COUNT; |
843 | callcfsm.strEvent = strEvent; | 841 | callcfsm.strEvent = strEvent; |
844 | callcfsm.strState = strState; | 842 | callcfsm.strState = strState; |
845 | return FsmNew(&callcfsm, fnlist, FNCOUNT); | 843 | return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist)); |
846 | } | 844 | } |
847 | 845 | ||
848 | void | 846 | void |
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 3d337d924c23..d110a77940a4 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c | |||
@@ -1506,8 +1506,6 @@ hfcpci_bh(struct work_struct *work) | |||
1506 | u_long flags; | 1506 | u_long flags; |
1507 | // struct PStack *stptr; | 1507 | // struct PStack *stptr; |
1508 | 1508 | ||
1509 | if (!cs) | ||
1510 | return; | ||
1511 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { | 1509 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { |
1512 | if (!cs->hw.hfcpci.nt_mode) | 1510 | if (!cs->hw.hfcpci.nt_mode) |
1513 | switch (cs->dc.hfcpci.ph_state) { | 1511 | switch (cs->dc.hfcpci.ph_state) { |
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index d92e8d6c2ae2..419f87cad8cb 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c | |||
@@ -1255,8 +1255,6 @@ hfcsx_bh(struct work_struct *work) | |||
1255 | container_of(work, struct IsdnCardState, tqueue); | 1255 | container_of(work, struct IsdnCardState, tqueue); |
1256 | u_long flags; | 1256 | u_long flags; |
1257 | 1257 | ||
1258 | if (!cs) | ||
1259 | return; | ||
1260 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { | 1258 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { |
1261 | if (!cs->hw.hfcsx.nt_mode) | 1259 | if (!cs->hw.hfcsx.nt_mode) |
1262 | switch (cs->dc.hfcsx.ph_state) { | 1260 | switch (cs->dc.hfcsx.ph_state) { |
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index 682cac32f259..9aba646ba221 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c | |||
@@ -83,8 +83,6 @@ icc_bh(struct work_struct *work) | |||
83 | container_of(work, struct IsdnCardState, tqueue); | 83 | container_of(work, struct IsdnCardState, tqueue); |
84 | struct PStack *stptr; | 84 | struct PStack *stptr; |
85 | 85 | ||
86 | if (!cs) | ||
87 | return; | ||
88 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { | 86 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { |
89 | if (cs->debug) | 87 | if (cs->debug) |
90 | debugl1(cs, "D-Channel Busy cleared"); | 88 | debugl1(cs, "D-Channel Busy cleared"); |
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 07b1673122b8..a19354d94343 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c | |||
@@ -86,8 +86,6 @@ isac_bh(struct work_struct *work) | |||
86 | container_of(work, struct IsdnCardState, tqueue); | 86 | container_of(work, struct IsdnCardState, tqueue); |
87 | struct PStack *stptr; | 87 | struct PStack *stptr; |
88 | 88 | ||
89 | if (!cs) | ||
90 | return; | ||
91 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { | 89 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { |
92 | if (cs->debug) | 90 | if (cs->debug) |
93 | debugl1(cs, "D-Channel Busy cleared"); | 91 | debugl1(cs, "D-Channel Busy cleared"); |
diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h deleted file mode 100644 index cf0a95a24015..000000000000 --- a/drivers/isdn/hisax/isdnhdlc.h +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | /* | ||
2 | * isdnhdlc.h -- General purpose ISDN HDLC decoder. | ||
3 | * | ||
4 | * Implementation of a HDLC decoder/encoder in software. | ||
5 | * Neccessary because some ISDN devices don't have HDLC | ||
6 | * controllers. Also included: a bit reversal table. | ||
7 | * | ||
8 | *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de> | ||
9 | * 2001 Frode Isaksen <fisaksen@bewan.com> | ||
10 | * 2001 Kai Germaschewski <kai.germaschewski@gmx.de> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #ifndef __ISDNHDLC_H__ | ||
28 | #define __ISDNHDLC_H__ | ||
29 | |||
30 | struct isdnhdlc_vars { | ||
31 | int bit_shift; | ||
32 | int hdlc_bits1; | ||
33 | int data_bits; | ||
34 | int ffbit_shift; // encoding only | ||
35 | int state; | ||
36 | int dstpos; | ||
37 | |||
38 | unsigned short crc; | ||
39 | |||
40 | unsigned char cbin; | ||
41 | unsigned char shift_reg; | ||
42 | unsigned char ffvalue; | ||
43 | |||
44 | unsigned int data_received:1; // set if transferring data | ||
45 | unsigned int dchannel:1; // set if D channel (send idle instead of flags) | ||
46 | unsigned int do_adapt56:1; // set if 56K adaptation | ||
47 | unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag | ||
48 | }; | ||
49 | |||
50 | |||
51 | /* | ||
52 | The return value from isdnhdlc_decode is | ||
53 | the frame length, 0 if no complete frame was decoded, | ||
54 | or a negative error number | ||
55 | */ | ||
56 | #define HDLC_FRAMING_ERROR 1 | ||
57 | #define HDLC_CRC_ERROR 2 | ||
58 | #define HDLC_LENGTH_ERROR 3 | ||
59 | |||
60 | extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); | ||
61 | |||
62 | extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, | ||
63 | unsigned char *dst, int dsize); | ||
64 | |||
65 | extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); | ||
66 | |||
67 | extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, | ||
68 | unsigned char *dst,int dsize); | ||
69 | |||
70 | #endif /* __ISDNHDLC_H__ */ | ||
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 317f16f516f2..9ce6abe05b1a 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c | |||
@@ -647,8 +647,6 @@ static struct FsmNode L1SFnList[] __initdata = | |||
647 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, | 647 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, |
648 | }; | 648 | }; |
649 | 649 | ||
650 | #define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) | ||
651 | |||
652 | #ifdef HISAX_UINTERFACE | 650 | #ifdef HISAX_UINTERFACE |
653 | static void | 651 | static void |
654 | l1_deact_req_u(struct FsmInst *fi, int event, void *arg) | 652 | l1_deact_req_u(struct FsmInst *fi, int event, void *arg) |
@@ -706,8 +704,6 @@ static struct FsmNode L1UFnList[] __initdata = | |||
706 | {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, | 704 | {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, |
707 | }; | 705 | }; |
708 | 706 | ||
709 | #define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) | ||
710 | |||
711 | #endif | 707 | #endif |
712 | 708 | ||
713 | static void | 709 | static void |
@@ -754,8 +750,6 @@ static struct FsmNode L1BFnList[] __initdata = | |||
754 | {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, | 750 | {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, |
755 | }; | 751 | }; |
756 | 752 | ||
757 | #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) | ||
758 | |||
759 | int __init | 753 | int __init |
760 | Isdnl1New(void) | 754 | Isdnl1New(void) |
761 | { | 755 | { |
@@ -765,7 +759,7 @@ Isdnl1New(void) | |||
765 | l1fsm_s.event_count = L1_EVENT_COUNT; | 759 | l1fsm_s.event_count = L1_EVENT_COUNT; |
766 | l1fsm_s.strEvent = strL1Event; | 760 | l1fsm_s.strEvent = strL1Event; |
767 | l1fsm_s.strState = strL1SState; | 761 | l1fsm_s.strState = strL1SState; |
768 | retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); | 762 | retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); |
769 | if (retval) | 763 | if (retval) |
770 | return retval; | 764 | return retval; |
771 | 765 | ||
@@ -773,7 +767,7 @@ Isdnl1New(void) | |||
773 | l1fsm_b.event_count = L1_EVENT_COUNT; | 767 | l1fsm_b.event_count = L1_EVENT_COUNT; |
774 | l1fsm_b.strEvent = strL1Event; | 768 | l1fsm_b.strEvent = strL1Event; |
775 | l1fsm_b.strState = strL1BState; | 769 | l1fsm_b.strState = strL1BState; |
776 | retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT); | 770 | retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList)); |
777 | if (retval) { | 771 | if (retval) { |
778 | FsmFree(&l1fsm_s); | 772 | FsmFree(&l1fsm_s); |
779 | return retval; | 773 | return retval; |
@@ -783,7 +777,7 @@ Isdnl1New(void) | |||
783 | l1fsm_u.event_count = L1_EVENT_COUNT; | 777 | l1fsm_u.event_count = L1_EVENT_COUNT; |
784 | l1fsm_u.strEvent = strL1Event; | 778 | l1fsm_u.strEvent = strL1Event; |
785 | l1fsm_u.strState = strL1UState; | 779 | l1fsm_u.strState = strL1UState; |
786 | retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); | 780 | retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList)); |
787 | if (retval) { | 781 | if (retval) { |
788 | FsmFree(&l1fsm_s); | 782 | FsmFree(&l1fsm_s); |
789 | FsmFree(&l1fsm_b); | 783 | FsmFree(&l1fsm_b); |
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 3446f249d675..7b9496a63b5f 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c | |||
@@ -1623,8 +1623,6 @@ static struct FsmNode L2FnList[] __initdata = | |||
1623 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, | 1623 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, |
1624 | }; | 1624 | }; |
1625 | 1625 | ||
1626 | #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) | ||
1627 | |||
1628 | static void | 1626 | static void |
1629 | isdnl2_l1l2(struct PStack *st, int pr, void *arg) | 1627 | isdnl2_l1l2(struct PStack *st, int pr, void *arg) |
1630 | { | 1628 | { |
@@ -1836,7 +1834,7 @@ Isdnl2New(void) | |||
1836 | l2fsm.event_count = L2_EVENT_COUNT; | 1834 | l2fsm.event_count = L2_EVENT_COUNT; |
1837 | l2fsm.strEvent = strL2Event; | 1835 | l2fsm.strEvent = strL2Event; |
1838 | l2fsm.strState = strL2State; | 1836 | l2fsm.strState = strL2State; |
1839 | return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT); | 1837 | return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); |
1840 | } | 1838 | } |
1841 | 1839 | ||
1842 | void | 1840 | void |
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index 935f23356fae..06766022d3ae 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c | |||
@@ -543,8 +543,6 @@ static struct FsmNode L3FnList[] __initdata = | |||
543 | }; | 543 | }; |
544 | /* *INDENT-ON* */ | 544 | /* *INDENT-ON* */ |
545 | 545 | ||
546 | #define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode)) | ||
547 | |||
548 | void | 546 | void |
549 | l3_msg(struct PStack *st, int pr, void *arg) | 547 | l3_msg(struct PStack *st, int pr, void *arg) |
550 | { | 548 | { |
@@ -587,7 +585,7 @@ Isdnl3New(void) | |||
587 | l3fsm.event_count = L3_EVENT_COUNT; | 585 | l3fsm.event_count = L3_EVENT_COUNT; |
588 | l3fsm.strEvent = strL3Event; | 586 | l3fsm.strEvent = strL3Event; |
589 | l3fsm.strState = strL3State; | 587 | l3fsm.strState = strL3State; |
590 | return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT); | 588 | return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList)); |
591 | } | 589 | } |
592 | 590 | ||
593 | void | 591 | void |
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index c5c36eeff261..b0554f80bfb3 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c | |||
@@ -698,9 +698,6 @@ static struct stateentry downstl[] = | |||
698 | CC_T308_2, l3_1tr6_t308_2}, | 698 | CC_T308_2, l3_1tr6_t308_2}, |
699 | }; | 699 | }; |
700 | 700 | ||
701 | #define DOWNSTL_LEN \ | ||
702 | (sizeof(downstl) / sizeof(struct stateentry)) | ||
703 | |||
704 | static struct stateentry datastln1[] = | 701 | static struct stateentry datastln1[] = |
705 | { | 702 | { |
706 | {SBIT(0), | 703 | {SBIT(0), |
@@ -735,9 +732,6 @@ static struct stateentry datastln1[] = | |||
735 | MT_N1_REL_ACK, l3_1tr6_rel_ack} | 732 | MT_N1_REL_ACK, l3_1tr6_rel_ack} |
736 | }; | 733 | }; |
737 | 734 | ||
738 | #define DATASTLN1_LEN \ | ||
739 | (sizeof(datastln1) / sizeof(struct stateentry)) | ||
740 | |||
741 | static struct stateentry manstatelist[] = | 735 | static struct stateentry manstatelist[] = |
742 | { | 736 | { |
743 | {SBIT(2), | 737 | {SBIT(2), |
@@ -746,8 +740,6 @@ static struct stateentry manstatelist[] = | |||
746 | DL_RELEASE | INDICATION, l3_1tr6_dl_release}, | 740 | DL_RELEASE | INDICATION, l3_1tr6_dl_release}, |
747 | }; | 741 | }; |
748 | 742 | ||
749 | #define MANSLLEN \ | ||
750 | (sizeof(manstatelist) / sizeof(struct stateentry)) | ||
751 | /* *INDENT-ON* */ | 743 | /* *INDENT-ON* */ |
752 | 744 | ||
753 | static void | 745 | static void |
@@ -840,11 +832,11 @@ up1tr6(struct PStack *st, int pr, void *arg) | |||
840 | mt = MT_N1_INVALID; | 832 | mt = MT_N1_INVALID; |
841 | } | 833 | } |
842 | } | 834 | } |
843 | for (i = 0; i < DATASTLN1_LEN; i++) | 835 | for (i = 0; i < ARRAY_SIZE(datastln1); i++) |
844 | if ((mt == datastln1[i].primitive) && | 836 | if ((mt == datastln1[i].primitive) && |
845 | ((1 << proc->state) & datastln1[i].state)) | 837 | ((1 << proc->state) & datastln1[i].state)) |
846 | break; | 838 | break; |
847 | if (i == DATASTLN1_LEN) { | 839 | if (i == ARRAY_SIZE(datastln1)) { |
848 | dev_kfree_skb(skb); | 840 | dev_kfree_skb(skb); |
849 | if (st->l3.debug & L3_DEB_STATE) { | 841 | if (st->l3.debug & L3_DEB_STATE) { |
850 | sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", | 842 | sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", |
@@ -892,11 +884,11 @@ down1tr6(struct PStack *st, int pr, void *arg) | |||
892 | proc = arg; | 884 | proc = arg; |
893 | } | 885 | } |
894 | 886 | ||
895 | for (i = 0; i < DOWNSTL_LEN; i++) | 887 | for (i = 0; i < ARRAY_SIZE(downstl); i++) |
896 | if ((pr == downstl[i].primitive) && | 888 | if ((pr == downstl[i].primitive) && |
897 | ((1 << proc->state) & downstl[i].state)) | 889 | ((1 << proc->state) & downstl[i].state)) |
898 | break; | 890 | break; |
899 | if (i == DOWNSTL_LEN) { | 891 | if (i == ARRAY_SIZE(downstl)) { |
900 | if (st->l3.debug & L3_DEB_STATE) { | 892 | if (st->l3.debug & L3_DEB_STATE) { |
901 | sprintf(tmp, "down1tr6 state %d prim %d unhandled", | 893 | sprintf(tmp, "down1tr6 state %d prim %d unhandled", |
902 | proc->state, pr); | 894 | proc->state, pr); |
@@ -922,11 +914,11 @@ man1tr6(struct PStack *st, int pr, void *arg) | |||
922 | printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); | 914 | printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); |
923 | return; | 915 | return; |
924 | } | 916 | } |
925 | for (i = 0; i < MANSLLEN; i++) | 917 | for (i = 0; i < ARRAY_SIZE(manstatelist); i++) |
926 | if ((pr == manstatelist[i].primitive) && | 918 | if ((pr == manstatelist[i].primitive) && |
927 | ((1 << proc->state) & manstatelist[i].state)) | 919 | ((1 << proc->state) & manstatelist[i].state)) |
928 | break; | 920 | break; |
929 | if (i == MANSLLEN) { | 921 | if (i == ARRAY_SIZE(manstatelist)) { |
930 | if (st->l3.debug & L3_DEB_STATE) { | 922 | if (st->l3.debug & L3_DEB_STATE) { |
931 | l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", | 923 | l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", |
932 | proc->callref & 0x7f, proc->state, pr); | 924 | proc->callref & 0x7f, proc->state, pr); |
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 99feae8b9210..a12fa4d34903 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c | |||
@@ -2820,9 +2820,6 @@ static struct stateentry downstatelist[] = | |||
2820 | CC_T309, l3dss1_dl_release}, | 2820 | CC_T309, l3dss1_dl_release}, |
2821 | }; | 2821 | }; |
2822 | 2822 | ||
2823 | #define DOWNSLLEN \ | ||
2824 | (sizeof(downstatelist) / sizeof(struct stateentry)) | ||
2825 | |||
2826 | static struct stateentry datastatelist[] = | 2823 | static struct stateentry datastatelist[] = |
2827 | { | 2824 | { |
2828 | {ALL_STATES, | 2825 | {ALL_STATES, |
@@ -2875,9 +2872,6 @@ static struct stateentry datastatelist[] = | |||
2875 | MT_RESUME_REJECT, l3dss1_resume_rej}, | 2872 | MT_RESUME_REJECT, l3dss1_resume_rej}, |
2876 | }; | 2873 | }; |
2877 | 2874 | ||
2878 | #define DATASLLEN \ | ||
2879 | (sizeof(datastatelist) / sizeof(struct stateentry)) | ||
2880 | |||
2881 | static struct stateentry globalmes_list[] = | 2875 | static struct stateentry globalmes_list[] = |
2882 | { | 2876 | { |
2883 | {ALL_STATES, | 2877 | {ALL_STATES, |
@@ -2888,8 +2882,6 @@ static struct stateentry globalmes_list[] = | |||
2888 | MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, | 2882 | MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, |
2889 | */ | 2883 | */ |
2890 | }; | 2884 | }; |
2891 | #define GLOBALM_LEN \ | ||
2892 | (sizeof(globalmes_list) / sizeof(struct stateentry)) | ||
2893 | 2885 | ||
2894 | static struct stateentry manstatelist[] = | 2886 | static struct stateentry manstatelist[] = |
2895 | { | 2887 | { |
@@ -2903,8 +2895,6 @@ static struct stateentry manstatelist[] = | |||
2903 | DL_RELEASE | INDICATION, l3dss1_dl_release}, | 2895 | DL_RELEASE | INDICATION, l3dss1_dl_release}, |
2904 | }; | 2896 | }; |
2905 | 2897 | ||
2906 | #define MANSLLEN \ | ||
2907 | (sizeof(manstatelist) / sizeof(struct stateentry)) | ||
2908 | /* *INDENT-ON* */ | 2898 | /* *INDENT-ON* */ |
2909 | 2899 | ||
2910 | 2900 | ||
@@ -2918,11 +2908,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) | |||
2918 | struct l3_process *proc = st->l3.global; | 2908 | struct l3_process *proc = st->l3.global; |
2919 | 2909 | ||
2920 | proc->callref = skb->data[2]; /* cr flag */ | 2910 | proc->callref = skb->data[2]; /* cr flag */ |
2921 | for (i = 0; i < GLOBALM_LEN; i++) | 2911 | for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) |
2922 | if ((mt == globalmes_list[i].primitive) && | 2912 | if ((mt == globalmes_list[i].primitive) && |
2923 | ((1 << proc->state) & globalmes_list[i].state)) | 2913 | ((1 << proc->state) & globalmes_list[i].state)) |
2924 | break; | 2914 | break; |
2925 | if (i == GLOBALM_LEN) { | 2915 | if (i == ARRAY_SIZE(globalmes_list)) { |
2926 | if (st->l3.debug & L3_DEB_STATE) { | 2916 | if (st->l3.debug & L3_DEB_STATE) { |
2927 | l3_debug(st, "dss1 global state %d mt %x unhandled", | 2917 | l3_debug(st, "dss1 global state %d mt %x unhandled", |
2928 | proc->state, mt); | 2918 | proc->state, mt); |
@@ -3097,11 +3087,11 @@ dss1up(struct PStack *st, int pr, void *arg) | |||
3097 | } | 3087 | } |
3098 | if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) | 3088 | if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) |
3099 | l3dss1_deliver_display(proc, pr, p); /* Display IE included */ | 3089 | l3dss1_deliver_display(proc, pr, p); /* Display IE included */ |
3100 | for (i = 0; i < DATASLLEN; i++) | 3090 | for (i = 0; i < ARRAY_SIZE(datastatelist); i++) |
3101 | if ((mt == datastatelist[i].primitive) && | 3091 | if ((mt == datastatelist[i].primitive) && |
3102 | ((1 << proc->state) & datastatelist[i].state)) | 3092 | ((1 << proc->state) & datastatelist[i].state)) |
3103 | break; | 3093 | break; |
3104 | if (i == DATASLLEN) { | 3094 | if (i == ARRAY_SIZE(datastatelist)) { |
3105 | if (st->l3.debug & L3_DEB_STATE) { | 3095 | if (st->l3.debug & L3_DEB_STATE) { |
3106 | l3_debug(st, "dss1up%sstate %d mt %#x unhandled", | 3096 | l3_debug(st, "dss1up%sstate %d mt %#x unhandled", |
3107 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | 3097 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", |
@@ -3156,11 +3146,11 @@ dss1down(struct PStack *st, int pr, void *arg) | |||
3156 | return; | 3146 | return; |
3157 | } | 3147 | } |
3158 | 3148 | ||
3159 | for (i = 0; i < DOWNSLLEN; i++) | 3149 | for (i = 0; i < ARRAY_SIZE(downstatelist); i++) |
3160 | if ((pr == downstatelist[i].primitive) && | 3150 | if ((pr == downstatelist[i].primitive) && |
3161 | ((1 << proc->state) & downstatelist[i].state)) | 3151 | ((1 << proc->state) & downstatelist[i].state)) |
3162 | break; | 3152 | break; |
3163 | if (i == DOWNSLLEN) { | 3153 | if (i == ARRAY_SIZE(downstatelist)) { |
3164 | if (st->l3.debug & L3_DEB_STATE) { | 3154 | if (st->l3.debug & L3_DEB_STATE) { |
3165 | l3_debug(st, "dss1down state %d prim %#x unhandled", | 3155 | l3_debug(st, "dss1down state %d prim %#x unhandled", |
3166 | proc->state, pr); | 3156 | proc->state, pr); |
@@ -3184,11 +3174,11 @@ dss1man(struct PStack *st, int pr, void *arg) | |||
3184 | printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); | 3174 | printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); |
3185 | return; | 3175 | return; |
3186 | } | 3176 | } |
3187 | for (i = 0; i < MANSLLEN; i++) | 3177 | for (i = 0; i < ARRAY_SIZE(manstatelist); i++) |
3188 | if ((pr == manstatelist[i].primitive) && | 3178 | if ((pr == manstatelist[i].primitive) && |
3189 | ((1 << proc->state) & manstatelist[i].state)) | 3179 | ((1 << proc->state) & manstatelist[i].state)) |
3190 | break; | 3180 | break; |
3191 | if (i == MANSLLEN) { | 3181 | if (i == ARRAY_SIZE(manstatelist)) { |
3192 | if (st->l3.debug & L3_DEB_STATE) { | 3182 | if (st->l3.debug & L3_DEB_STATE) { |
3193 | l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", | 3183 | l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", |
3194 | proc->callref & 0x7f, proc->state, pr); | 3184 | proc->callref & 0x7f, proc->state, pr); |
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index f7041d5ba64e..4622d43c7e10 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c | |||
@@ -2755,9 +2755,6 @@ static struct stateentry downstatelist[] = | |||
2755 | CC_TSPID, l3ni1_spid_tout }, | 2755 | CC_TSPID, l3ni1_spid_tout }, |
2756 | }; | 2756 | }; |
2757 | 2757 | ||
2758 | #define DOWNSLLEN \ | ||
2759 | (sizeof(downstatelist) / sizeof(struct stateentry)) | ||
2760 | |||
2761 | static struct stateentry datastatelist[] = | 2758 | static struct stateentry datastatelist[] = |
2762 | { | 2759 | { |
2763 | {ALL_STATES, | 2760 | {ALL_STATES, |
@@ -2810,9 +2807,6 @@ static struct stateentry datastatelist[] = | |||
2810 | MT_RESUME_REJECT, l3ni1_resume_rej}, | 2807 | MT_RESUME_REJECT, l3ni1_resume_rej}, |
2811 | }; | 2808 | }; |
2812 | 2809 | ||
2813 | #define DATASLLEN \ | ||
2814 | (sizeof(datastatelist) / sizeof(struct stateentry)) | ||
2815 | |||
2816 | static struct stateentry globalmes_list[] = | 2810 | static struct stateentry globalmes_list[] = |
2817 | { | 2811 | { |
2818 | {ALL_STATES, | 2812 | {ALL_STATES, |
@@ -2825,8 +2819,6 @@ static struct stateentry globalmes_list[] = | |||
2825 | { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, | 2819 | { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, |
2826 | { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, | 2820 | { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, |
2827 | }; | 2821 | }; |
2828 | #define GLOBALM_LEN \ | ||
2829 | (sizeof(globalmes_list) / sizeof(struct stateentry)) | ||
2830 | 2822 | ||
2831 | static struct stateentry manstatelist[] = | 2823 | static struct stateentry manstatelist[] = |
2832 | { | 2824 | { |
@@ -2840,8 +2832,6 @@ static struct stateentry manstatelist[] = | |||
2840 | DL_RELEASE | INDICATION, l3ni1_dl_release}, | 2832 | DL_RELEASE | INDICATION, l3ni1_dl_release}, |
2841 | }; | 2833 | }; |
2842 | 2834 | ||
2843 | #define MANSLLEN \ | ||
2844 | (sizeof(manstatelist) / sizeof(struct stateentry)) | ||
2845 | /* *INDENT-ON* */ | 2835 | /* *INDENT-ON* */ |
2846 | 2836 | ||
2847 | 2837 | ||
@@ -2858,11 +2848,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) | |||
2858 | proc->callref = skb->data[2]; /* cr flag */ | 2848 | proc->callref = skb->data[2]; /* cr flag */ |
2859 | else | 2849 | else |
2860 | proc->callref = 0; | 2850 | proc->callref = 0; |
2861 | for (i = 0; i < GLOBALM_LEN; i++) | 2851 | for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) |
2862 | if ((mt == globalmes_list[i].primitive) && | 2852 | if ((mt == globalmes_list[i].primitive) && |
2863 | ((1 << proc->state) & globalmes_list[i].state)) | 2853 | ((1 << proc->state) & globalmes_list[i].state)) |
2864 | break; | 2854 | break; |
2865 | if (i == GLOBALM_LEN) { | 2855 | if (i == ARRAY_SIZE(globalmes_list)) { |
2866 | if (st->l3.debug & L3_DEB_STATE) { | 2856 | if (st->l3.debug & L3_DEB_STATE) { |
2867 | l3_debug(st, "ni1 global state %d mt %x unhandled", | 2857 | l3_debug(st, "ni1 global state %d mt %x unhandled", |
2868 | proc->state, mt); | 2858 | proc->state, mt); |
@@ -3049,11 +3039,11 @@ ni1up(struct PStack *st, int pr, void *arg) | |||
3049 | } | 3039 | } |
3050 | if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) | 3040 | if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) |
3051 | l3ni1_deliver_display(proc, pr, p); /* Display IE included */ | 3041 | l3ni1_deliver_display(proc, pr, p); /* Display IE included */ |
3052 | for (i = 0; i < DATASLLEN; i++) | 3042 | for (i = 0; i < ARRAY_SIZE(datastatelist); i++) |
3053 | if ((mt == datastatelist[i].primitive) && | 3043 | if ((mt == datastatelist[i].primitive) && |
3054 | ((1 << proc->state) & datastatelist[i].state)) | 3044 | ((1 << proc->state) & datastatelist[i].state)) |
3055 | break; | 3045 | break; |
3056 | if (i == DATASLLEN) { | 3046 | if (i == ARRAY_SIZE(datastatelist)) { |
3057 | if (st->l3.debug & L3_DEB_STATE) { | 3047 | if (st->l3.debug & L3_DEB_STATE) { |
3058 | l3_debug(st, "ni1up%sstate %d mt %#x unhandled", | 3048 | l3_debug(st, "ni1up%sstate %d mt %#x unhandled", |
3059 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | 3049 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", |
@@ -3108,11 +3098,11 @@ ni1down(struct PStack *st, int pr, void *arg) | |||
3108 | return; | 3098 | return; |
3109 | } | 3099 | } |
3110 | 3100 | ||
3111 | for (i = 0; i < DOWNSLLEN; i++) | 3101 | for (i = 0; i < ARRAY_SIZE(downstatelist); i++) |
3112 | if ((pr == downstatelist[i].primitive) && | 3102 | if ((pr == downstatelist[i].primitive) && |
3113 | ((1 << proc->state) & downstatelist[i].state)) | 3103 | ((1 << proc->state) & downstatelist[i].state)) |
3114 | break; | 3104 | break; |
3115 | if (i == DOWNSLLEN) { | 3105 | if (i == ARRAY_SIZE(downstatelist)) { |
3116 | if (st->l3.debug & L3_DEB_STATE) { | 3106 | if (st->l3.debug & L3_DEB_STATE) { |
3117 | l3_debug(st, "ni1down state %d prim %#x unhandled", | 3107 | l3_debug(st, "ni1down state %d prim %#x unhandled", |
3118 | proc->state, pr); | 3108 | proc->state, pr); |
@@ -3136,11 +3126,11 @@ ni1man(struct PStack *st, int pr, void *arg) | |||
3136 | printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); | 3126 | printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); |
3137 | return; | 3127 | return; |
3138 | } | 3128 | } |
3139 | for (i = 0; i < MANSLLEN; i++) | 3129 | for (i = 0; i < ARRAY_SIZE(manstatelist); i++) |
3140 | if ((pr == manstatelist[i].primitive) && | 3130 | if ((pr == manstatelist[i].primitive) && |
3141 | ((1 << proc->state) & manstatelist[i].state)) | 3131 | ((1 << proc->state) & manstatelist[i].state)) |
3142 | break; | 3132 | break; |
3143 | if (i == MANSLLEN) { | 3133 | if (i == ARRAY_SIZE(manstatelist)) { |
3144 | if (st->l3.debug & L3_DEB_STATE) { | 3134 | if (st->l3.debug & L3_DEB_STATE) { |
3145 | l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", | 3135 | l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", |
3146 | proc->callref & 0x7f, proc->state, pr); | 3136 | proc->callref & 0x7f, proc->state, pr); |
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index aacbf0d14b64..8b853d58e820 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c | |||
@@ -140,7 +140,7 @@ struct MessageType { | |||
140 | } | 140 | } |
141 | }; | 141 | }; |
142 | 142 | ||
143 | #define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) | 143 | #define MTSIZE ARRAY_SIZE(mtlist) |
144 | 144 | ||
145 | static | 145 | static |
146 | struct MessageType mt_n0[] = | 146 | struct MessageType mt_n0[] = |
@@ -157,7 +157,7 @@ struct MessageType mt_n0[] = | |||
157 | {MT_N0_CLO_ACK, "CLOse ACKnowledge"} | 157 | {MT_N0_CLO_ACK, "CLOse ACKnowledge"} |
158 | }; | 158 | }; |
159 | 159 | ||
160 | #define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType)) | 160 | #define MT_N0_LEN ARRAY_SIZE(mt_n0) |
161 | 161 | ||
162 | static | 162 | static |
163 | struct MessageType mt_n1[] = | 163 | struct MessageType mt_n1[] = |
@@ -194,7 +194,7 @@ struct MessageType mt_n1[] = | |||
194 | {MT_N1_STAT, "STATus"} | 194 | {MT_N1_STAT, "STATus"} |
195 | }; | 195 | }; |
196 | 196 | ||
197 | #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) | 197 | #define MT_N1_LEN ARRAY_SIZE(mt_n1) |
198 | 198 | ||
199 | 199 | ||
200 | static int | 200 | static int |
@@ -438,7 +438,7 @@ struct CauseValue { | |||
438 | }, | 438 | }, |
439 | }; | 439 | }; |
440 | 440 | ||
441 | #define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue) | 441 | #define CVSIZE ARRAY_SIZE(cvlist) |
442 | 442 | ||
443 | static | 443 | static |
444 | int | 444 | int |
@@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] = | |||
516 | {CAUSE_UserInfoDiscarded, "User Info Discarded"} | 516 | {CAUSE_UserInfoDiscarded, "User Info Discarded"} |
517 | }; | 517 | }; |
518 | 518 | ||
519 | static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); | 519 | static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); |
520 | 520 | ||
521 | static int | 521 | static int |
522 | prcause_1tr6(char *dest, u_char * p) | 522 | prcause_1tr6(char *dest, u_char * p) |
@@ -865,7 +865,7 @@ struct DTag { /* Display tags */ | |||
865 | { 0x96, "Redirection name" }, | 865 | { 0x96, "Redirection name" }, |
866 | { 0x9e, "Text" }, | 866 | { 0x9e, "Text" }, |
867 | }; | 867 | }; |
868 | #define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) | 868 | #define DTAGSIZE ARRAY_SIZE(dtaglist) |
869 | 869 | ||
870 | static int | 870 | static int |
871 | disptext_ni1(char *dest, u_char * p) | 871 | disptext_ni1(char *dest, u_char * p) |
@@ -1074,7 +1074,7 @@ struct InformationElement { | |||
1074 | }; | 1074 | }; |
1075 | 1075 | ||
1076 | 1076 | ||
1077 | #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) | 1077 | #define IESIZE ARRAY_SIZE(ielist) |
1078 | 1078 | ||
1079 | static | 1079 | static |
1080 | struct InformationElement ielist_ni1[] = { | 1080 | struct InformationElement ielist_ni1[] = { |
@@ -1102,7 +1102,7 @@ struct InformationElement ielist_ni1[] = { | |||
1102 | }; | 1102 | }; |
1103 | 1103 | ||
1104 | 1104 | ||
1105 | #define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) | 1105 | #define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) |
1106 | 1106 | ||
1107 | static | 1107 | static |
1108 | struct InformationElement ielist_ni1_cs5[] = { | 1108 | struct InformationElement ielist_ni1_cs5[] = { |
@@ -1110,14 +1110,14 @@ struct InformationElement ielist_ni1_cs5[] = { | |||
1110 | { 0x2a, "Display text", disptext_ni1 }, | 1110 | { 0x2a, "Display text", disptext_ni1 }, |
1111 | }; | 1111 | }; |
1112 | 1112 | ||
1113 | #define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) | 1113 | #define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) |
1114 | 1114 | ||
1115 | static | 1115 | static |
1116 | struct InformationElement ielist_ni1_cs6[] = { | 1116 | struct InformationElement ielist_ni1_cs6[] = { |
1117 | { 0x7b, "Call appearance", general_ni1 }, | 1117 | { 0x7b, "Call appearance", general_ni1 }, |
1118 | }; | 1118 | }; |
1119 | 1119 | ||
1120 | #define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) | 1120 | #define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) |
1121 | 1121 | ||
1122 | static struct InformationElement we_0[] = | 1122 | static struct InformationElement we_0[] = |
1123 | { | 1123 | { |
@@ -1133,7 +1133,7 @@ static struct InformationElement we_0[] = | |||
1133 | {WE0_userInfo, "User Info", general} | 1133 | {WE0_userInfo, "User Info", general} |
1134 | }; | 1134 | }; |
1135 | 1135 | ||
1136 | #define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement)) | 1136 | #define WE_0_LEN ARRAY_SIZE(we_0) |
1137 | 1137 | ||
1138 | static struct InformationElement we_6[] = | 1138 | static struct InformationElement we_6[] = |
1139 | { | 1139 | { |
@@ -1145,7 +1145,7 @@ static struct InformationElement we_6[] = | |||
1145 | {WE6_statusCalled, "Status Called", general}, | 1145 | {WE6_statusCalled, "Status Called", general}, |
1146 | {WE6_addTransAttr, "Additional Transmission Attributes", general} | 1146 | {WE6_addTransAttr, "Additional Transmission Attributes", general} |
1147 | }; | 1147 | }; |
1148 | #define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) | 1148 | #define WE_6_LEN ARRAY_SIZE(we_6) |
1149 | 1149 | ||
1150 | int | 1150 | int |
1151 | QuickHex(char *txt, u_char * p, int cnt) | 1151 | QuickHex(char *txt, u_char * p, int cnt) |
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index cff7a6354334..64f78a8c28c5 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h | |||
@@ -226,7 +226,7 @@ printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) | |||
226 | #define INFO(format, arg...) \ | 226 | #define INFO(format, arg...) \ |
227 | printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) | 227 | printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) |
228 | 228 | ||
229 | #include "isdnhdlc.h" | 229 | #include <linux/isdn/hdlc.h> |
230 | #include "fsm.h" | 230 | #include "fsm.h" |
231 | #include "hisax_if.h" | 231 | #include "hisax_if.h" |
232 | #include <linux/skbuff.h> | 232 | #include <linux/skbuff.h> |
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 0074b600a0ef..95b1cdd97958 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c | |||
@@ -218,7 +218,10 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode) | |||
218 | if (bcs->mode != L1_MODE_NULL) { | 218 | if (bcs->mode != L1_MODE_NULL) { |
219 | // Open the B channel | 219 | // Open the B channel |
220 | if (bcs->mode != L1_MODE_TRANS) { | 220 | if (bcs->mode != L1_MODE_TRANS) { |
221 | isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K); | 221 | u32 features = HDLC_BITREVERSE; |
222 | if (bcs->mode == L1_MODE_HDLC_56K) | ||
223 | features |= HDLC_56KBIT; | ||
224 | isdnhdlc_out_init(&b_out->hdlc_state, features); | ||
222 | } | 225 | } |
223 | st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL); | 226 | st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL); |
224 | 227 | ||
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 077991c1cd05..39e8e49cfd2d 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c | |||
@@ -417,7 +417,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg) | |||
417 | 417 | ||
418 | DBG(2,"len=%d",skb->len); | 418 | DBG(2,"len=%d",skb->len); |
419 | 419 | ||
420 | isdnhdlc_out_init(&d_out->hdlc_state, 1, 0); | 420 | isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE); |
421 | 421 | ||
422 | if (test_and_set_bit(buf_nr, &d_out->busy)) { | 422 | if (test_and_set_bit(buf_nr, &d_out->busy)) { |
423 | WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); | 423 | WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); |
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 2b3a055059ea..10d41c5d73ed 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c | |||
@@ -637,10 +637,13 @@ void st5481_in_mode(struct st5481_in *in, int mode) | |||
637 | usb_unlink_urb(in->urb[1]); | 637 | usb_unlink_urb(in->urb[1]); |
638 | 638 | ||
639 | if (in->mode != L1_MODE_NULL) { | 639 | if (in->mode != L1_MODE_NULL) { |
640 | if (in->mode != L1_MODE_TRANS) | 640 | if (in->mode != L1_MODE_TRANS) { |
641 | isdnhdlc_rcv_init(&in->hdlc_state, | 641 | u32 features = HDLC_BITREVERSE; |
642 | in->mode == L1_MODE_HDLC_56K); | 642 | |
643 | 643 | if (in->mode == L1_MODE_HDLC_56K) | |
644 | features |= HDLC_56KBIT; | ||
645 | isdnhdlc_rcv_init(&in->hdlc_state, features); | ||
646 | } | ||
644 | st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); | 647 | st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); |
645 | st5481_usb_device_ctrl_msg(in->adapter, in->counter, | 648 | st5481_usb_device_ctrl_msg(in->adapter, in->counter, |
646 | in->packet_size, | 649 | in->packet_size, |
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index ceb0df92fd3e..6e65424f1f04 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c | |||
@@ -447,8 +447,6 @@ static struct FsmNode TeiFnList[] __initdata = | |||
447 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | 447 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, |
448 | }; | 448 | }; |
449 | 449 | ||
450 | #define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode)) | ||
451 | |||
452 | int __init | 450 | int __init |
453 | TeiNew(void) | 451 | TeiNew(void) |
454 | { | 452 | { |
@@ -456,7 +454,7 @@ TeiNew(void) | |||
456 | teifsm.event_count = TEI_EVENT_COUNT; | 454 | teifsm.event_count = TEI_EVENT_COUNT; |
457 | teifsm.strEvent = strTeiEvent; | 455 | teifsm.strEvent = strTeiEvent; |
458 | teifsm.strState = strTeiState; | 456 | teifsm.strState = strTeiState; |
459 | return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT); | 457 | return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList)); |
460 | } | 458 | } |
461 | 459 | ||
462 | void | 460 | void |
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index bb1c8dd1a230..c4d862c11a60 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c | |||
@@ -105,8 +105,6 @@ W6692_bh(struct work_struct *work) | |||
105 | container_of(work, struct IsdnCardState, tqueue); | 105 | container_of(work, struct IsdnCardState, tqueue); |
106 | struct PStack *stptr; | 106 | struct PStack *stptr; |
107 | 107 | ||
108 | if (!cs) | ||
109 | return; | ||
110 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { | 108 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { |
111 | if (cs->debug) | 109 | if (cs->debug) |
112 | debugl1(cs, "D-Channel Busy cleared"); | 110 | debugl1(cs, "D-Channel Busy cleared"); |
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 579974cf4c9a..c73004b3b2ac 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c | |||
@@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) | |||
148 | if (lp->sk_count <= 3) { | 148 | if (lp->sk_count <= 3) { |
149 | schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); | 149 | schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); |
150 | } | 150 | } |
151 | return (0); /* success */ | 151 | return NETDEV_TX_OK; /* success */ |
152 | } /* net_send_packet */ | 152 | } /* net_send_packet */ |
153 | 153 | ||
154 | 154 | ||
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index ed3510f273d8..dd744ffd240b 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig | |||
@@ -2,6 +2,8 @@ | |||
2 | # Old ISDN4Linux config | 2 | # Old ISDN4Linux config |
3 | # | 3 | # |
4 | 4 | ||
5 | if ISDN_I4L | ||
6 | |||
5 | config ISDN_PPP | 7 | config ISDN_PPP |
6 | bool "Support synchronous PPP" | 8 | bool "Support synchronous PPP" |
7 | depends on INET | 9 | depends on INET |
@@ -135,3 +137,12 @@ source "drivers/isdn/act2000/Kconfig" | |||
135 | source "drivers/isdn/hysdn/Kconfig" | 137 | source "drivers/isdn/hysdn/Kconfig" |
136 | 138 | ||
137 | endmenu | 139 | endmenu |
140 | # end ISDN_I4L | ||
141 | endif | ||
142 | |||
143 | config ISDN_HDLC | ||
144 | tristate | ||
145 | depends on HISAX_ST5481 | ||
146 | select CRC_CCITT | ||
147 | select BITREVERSE | ||
148 | |||
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile index 49a06c0005dd..cb9d3bb9fae0 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_ISDN_I4L) += isdn.o | 5 | obj-$(CONFIG_ISDN_I4L) += isdn.o |
6 | obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o | 6 | obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o |
7 | obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o | ||
7 | 8 | ||
8 | # Multipart objects. | 9 | # Multipart objects. |
9 | 10 | ||
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index de4aad076ebc..57bf4bf50278 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c | |||
@@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) | |||
1051 | isdn_net_dev *nd; | 1051 | isdn_net_dev *nd; |
1052 | isdn_net_local *slp; | 1052 | isdn_net_local *slp; |
1053 | isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); | 1053 | isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); |
1054 | int retv = 0; | 1054 | int retv = NETDEV_TX_OK; |
1055 | 1055 | ||
1056 | if (((isdn_net_local *) netdev_priv(ndev))->master) { | 1056 | if (((isdn_net_local *) netdev_priv(ndev))->master) { |
1057 | printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); | 1057 | printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); |
1058 | dev_kfree_skb(skb); | 1058 | dev_kfree_skb(skb); |
1059 | return 0; | 1059 | return NETDEV_TX_OK; |
1060 | } | 1060 | } |
1061 | 1061 | ||
1062 | /* For the other encaps the header has already been built */ | 1062 | /* For the other encaps the header has already been built */ |
@@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1202 | if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { | 1202 | if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { |
1203 | isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); | 1203 | isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); |
1204 | dev_kfree_skb(skb); | 1204 | dev_kfree_skb(skb); |
1205 | return 0; | 1205 | return NETDEV_TX_OK; |
1206 | } | 1206 | } |
1207 | if (lp->phone[1]) { | 1207 | if (lp->phone[1]) { |
1208 | ulong flags; | 1208 | ulong flags; |
@@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1215 | if(time_before(jiffies, lp->dialwait_timer)) { | 1215 | if(time_before(jiffies, lp->dialwait_timer)) { |
1216 | isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); | 1216 | isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); |
1217 | dev_kfree_skb(skb); | 1217 | dev_kfree_skb(skb); |
1218 | return 0; | 1218 | return NETDEV_TX_OK; |
1219 | } else | 1219 | } else |
1220 | lp->dialwait_timer = 0; | 1220 | lp->dialwait_timer = 0; |
1221 | } | 1221 | } |
@@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1243 | isdn_net_unreachable(ndev, skb, | 1243 | isdn_net_unreachable(ndev, skb, |
1244 | "No channel"); | 1244 | "No channel"); |
1245 | dev_kfree_skb(skb); | 1245 | dev_kfree_skb(skb); |
1246 | return 0; | 1246 | return NETDEV_TX_OK; |
1247 | } | 1247 | } |
1248 | /* Log packet, which triggered dialing */ | 1248 | /* Log packet, which triggered dialing */ |
1249 | if (dev->net_verbose) | 1249 | if (dev->net_verbose) |
@@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1258 | dev_kfree_skb(skb); | 1258 | dev_kfree_skb(skb); |
1259 | isdn_net_unbind_channel(lp); | 1259 | isdn_net_unbind_channel(lp); |
1260 | spin_unlock_irqrestore(&dev->lock, flags); | 1260 | spin_unlock_irqrestore(&dev->lock, flags); |
1261 | return 0; /* STN (skb to nirvana) ;) */ | 1261 | return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */ |
1262 | } | 1262 | } |
1263 | #ifdef CONFIG_IPPP_FILTER | 1263 | #ifdef CONFIG_IPPP_FILTER |
1264 | if (isdn_ppp_autodial_filter(skb, lp)) { | 1264 | if (isdn_ppp_autodial_filter(skb, lp)) { |
@@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1267 | spin_unlock_irqrestore(&dev->lock, flags); | 1267 | spin_unlock_irqrestore(&dev->lock, flags); |
1268 | isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); | 1268 | isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); |
1269 | dev_kfree_skb(skb); | 1269 | dev_kfree_skb(skb); |
1270 | return 0; | 1270 | return NETDEV_TX_OK; |
1271 | } | 1271 | } |
1272 | #endif | 1272 | #endif |
1273 | spin_unlock_irqrestore(&dev->lock, flags); | 1273 | spin_unlock_irqrestore(&dev->lock, flags); |
@@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
1285 | isdn_net_unreachable(ndev, skb, | 1285 | isdn_net_unreachable(ndev, skb, |
1286 | "No phone number"); | 1286 | "No phone number"); |
1287 | dev_kfree_skb(skb); | 1287 | dev_kfree_skb(skb); |
1288 | return 0; | 1288 | return NETDEV_TX_OK; |
1289 | } | 1289 | } |
1290 | } else { | 1290 | } else { |
1291 | /* Device is connected to an ISDN channel */ | 1291 | /* Device is connected to an ISDN channel */ |
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index aa30b5cb3513..2d14b64202a3 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c | |||
@@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
1223 | isdn_net_dev *nd; | 1223 | isdn_net_dev *nd; |
1224 | unsigned int proto = PPP_IP; /* 0x21 */ | 1224 | unsigned int proto = PPP_IP; /* 0x21 */ |
1225 | struct ippp_struct *ipt,*ipts; | 1225 | struct ippp_struct *ipt,*ipts; |
1226 | int slot, retval = 0; | 1226 | int slot, retval = NETDEV_TX_OK; |
1227 | 1227 | ||
1228 | mlp = (isdn_net_local *) netdev_priv(netdev); | 1228 | mlp = (isdn_net_local *) netdev_priv(netdev); |
1229 | nd = mlp->netdev; /* get master lp */ | 1229 | nd = mlp->netdev; /* get master lp */ |
@@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
1240 | if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ | 1240 | if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ |
1241 | if (ipts->debug & 0x1) | 1241 | if (ipts->debug & 0x1) |
1242 | printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); | 1242 | printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); |
1243 | retval = 1; | 1243 | retval = NETDEV_TX_BUSY; |
1244 | goto out; | 1244 | goto out; |
1245 | } | 1245 | } |
1246 | 1246 | ||
@@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
1261 | lp = isdn_net_get_locked_lp(nd); | 1261 | lp = isdn_net_get_locked_lp(nd); |
1262 | if (!lp) { | 1262 | if (!lp) { |
1263 | printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); | 1263 | printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); |
1264 | retval = 1; | 1264 | retval = NETDEV_TX_BUSY; |
1265 | goto out; | 1265 | goto out; |
1266 | } | 1266 | } |
1267 | /* we have our lp locked from now on */ | 1267 | /* we have our lp locked from now on */ |
diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index c69a77a80062..c989aa35dc2f 100644 --- a/drivers/isdn/hisax/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c | |||
@@ -1,29 +1,32 @@ | |||
1 | /* | 1 | /* |
2 | * isdnhdlc.c -- General purpose ISDN HDLC decoder. | 2 | * isdnhdlc.c -- General purpose ISDN HDLC decoder. |
3 | * | 3 | * |
4 | *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de> | 4 | * Copyright (C) |
5 | * 2001 Frode Isaksen <fisaksen@bewan.com> | 5 | * 2009 Karsten Keil <keil@b1-systems.de> |
6 | * 2001 Kai Germaschewski <kai.germaschewski@gmx.de> | 6 | * 2002 Wolfgang Mües <wolfgang@iksw-muees.de> |
7 | * 2001 Frode Isaksen <fisaksen@bewan.com> | ||
8 | * 2001 Kai Germaschewski <kai.germaschewski@gmx.de> | ||
7 | * | 9 | * |
8 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 13 | * (at your option) any later version. |
12 | * | 14 | * |
13 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
17 | * | 19 | * |
18 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | */ | 23 | */ |
22 | 24 | ||
23 | #include <linux/module.h> | 25 | #include <linux/module.h> |
24 | #include <linux/init.h> | 26 | #include <linux/init.h> |
25 | #include <linux/crc-ccitt.h> | 27 | #include <linux/crc-ccitt.h> |
26 | #include "isdnhdlc.h" | 28 | #include <linux/isdn/hdlc.h> |
29 | #include <linux/bitrev.h> | ||
27 | 30 | ||
28 | /*-------------------------------------------------------------------*/ | 31 | /*-------------------------------------------------------------------*/ |
29 | 32 | ||
@@ -36,44 +39,32 @@ MODULE_LICENSE("GPL"); | |||
36 | /*-------------------------------------------------------------------*/ | 39 | /*-------------------------------------------------------------------*/ |
37 | 40 | ||
38 | enum { | 41 | enum { |
39 | HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, | 42 | HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, |
40 | HDLC_GET_DATA,HDLC_FAST_FLAG | 43 | HDLC_GET_DATA, HDLC_FAST_FLAG |
41 | }; | 44 | }; |
42 | 45 | ||
43 | enum { | 46 | enum { |
44 | HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, | 47 | HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, |
45 | HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, | 48 | HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, |
46 | HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, | 49 | HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, |
47 | HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED | 50 | HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE |
48 | }; | 51 | }; |
49 | 52 | ||
50 | void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) | 53 | void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) |
51 | { | 54 | { |
52 | hdlc->bit_shift = 0; | 55 | memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); |
53 | hdlc->hdlc_bits1 = 0; | ||
54 | hdlc->data_bits = 0; | ||
55 | hdlc->ffbit_shift = 0; | ||
56 | hdlc->data_received = 0; | ||
57 | hdlc->state = HDLC_GET_DATA; | 56 | hdlc->state = HDLC_GET_DATA; |
58 | hdlc->do_adapt56 = do_adapt56; | 57 | if (features & HDLC_56KBIT) |
59 | hdlc->dchannel = 0; | 58 | hdlc->do_adapt56 = 1; |
60 | hdlc->crc = 0; | 59 | if (features & HDLC_BITREVERSE) |
61 | hdlc->cbin = 0; | 60 | hdlc->do_bitreverse = 1; |
62 | hdlc->shift_reg = 0; | ||
63 | hdlc->ffvalue = 0; | ||
64 | hdlc->dstpos = 0; | ||
65 | } | 61 | } |
62 | EXPORT_SYMBOL(isdnhdlc_out_init); | ||
66 | 63 | ||
67 | void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) | 64 | void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) |
68 | { | 65 | { |
69 | hdlc->bit_shift = 0; | 66 | memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); |
70 | hdlc->hdlc_bits1 = 0; | 67 | if (features & HDLC_DCHANNEL) { |
71 | hdlc->data_bits = 0; | ||
72 | hdlc->ffbit_shift = 0; | ||
73 | hdlc->data_received = 0; | ||
74 | hdlc->do_closing = 0; | ||
75 | hdlc->ffvalue = 0; | ||
76 | if (is_d_channel) { | ||
77 | hdlc->dchannel = 1; | 68 | hdlc->dchannel = 1; |
78 | hdlc->state = HDLC_SEND_FIRST_FLAG; | 69 | hdlc->state = HDLC_SEND_FIRST_FLAG; |
79 | } else { | 70 | } else { |
@@ -82,16 +73,32 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada | |||
82 | hdlc->ffvalue = 0x7e; | 73 | hdlc->ffvalue = 0x7e; |
83 | } | 74 | } |
84 | hdlc->cbin = 0x7e; | 75 | hdlc->cbin = 0x7e; |
85 | hdlc->bit_shift = 0; | 76 | if (features & HDLC_56KBIT) { |
86 | if(do_adapt56){ | ||
87 | hdlc->do_adapt56 = 1; | 77 | hdlc->do_adapt56 = 1; |
88 | hdlc->data_bits = 0; | ||
89 | hdlc->state = HDLC_SENDFLAG_B0; | 78 | hdlc->state = HDLC_SENDFLAG_B0; |
90 | } else { | 79 | } else |
91 | hdlc->do_adapt56 = 0; | ||
92 | hdlc->data_bits = 8; | 80 | hdlc->data_bits = 8; |
81 | if (features & HDLC_BITREVERSE) | ||
82 | hdlc->do_bitreverse = 1; | ||
83 | } | ||
84 | EXPORT_SYMBOL(isdnhdlc_rcv_init); | ||
85 | |||
86 | static int | ||
87 | check_frame(struct isdnhdlc_vars *hdlc) | ||
88 | { | ||
89 | int status; | ||
90 | |||
91 | if (hdlc->dstpos < 2) /* too small - framing error */ | ||
92 | status = -HDLC_FRAMING_ERROR; | ||
93 | else if (hdlc->crc != 0xf0b8) /* crc error */ | ||
94 | status = -HDLC_CRC_ERROR; | ||
95 | else { | ||
96 | /* remove CRC */ | ||
97 | hdlc->dstpos -= 2; | ||
98 | /* good frame */ | ||
99 | status = hdlc->dstpos; | ||
93 | } | 100 | } |
94 | hdlc->shift_reg = 0; | 101 | return status; |
95 | } | 102 | } |
96 | 103 | ||
97 | /* | 104 | /* |
@@ -121,40 +128,67 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada | |||
121 | returns - number of decoded bytes in the destination buffer and status | 128 | returns - number of decoded bytes in the destination buffer and status |
122 | flag. | 129 | flag. |
123 | */ | 130 | */ |
124 | int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | 131 | int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, |
125 | int slen, int *count, unsigned char *dst, int dsize) | 132 | int *count, u8 *dst, int dsize) |
126 | { | 133 | { |
127 | int status=0; | 134 | int status = 0; |
128 | 135 | ||
129 | static const unsigned char fast_flag[]={ | 136 | static const unsigned char fast_flag[] = { |
130 | 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f | 137 | 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f |
131 | }; | 138 | }; |
132 | 139 | ||
133 | static const unsigned char fast_flag_value[]={ | 140 | static const unsigned char fast_flag_value[] = { |
134 | 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f | 141 | 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f |
135 | }; | 142 | }; |
136 | 143 | ||
137 | static const unsigned char fast_abort[]={ | 144 | static const unsigned char fast_abort[] = { |
138 | 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff | 145 | 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff |
139 | }; | 146 | }; |
140 | 147 | ||
148 | #define handle_fast_flag(h) \ | ||
149 | do {\ | ||
150 | if (h->cbin == fast_flag[h->bit_shift]) {\ | ||
151 | h->ffvalue = fast_flag_value[h->bit_shift];\ | ||
152 | h->state = HDLC_FAST_FLAG;\ | ||
153 | h->ffbit_shift = h->bit_shift;\ | ||
154 | h->bit_shift = 1;\ | ||
155 | } else {\ | ||
156 | h->state = HDLC_GET_DATA;\ | ||
157 | h->data_received = 0;\ | ||
158 | } \ | ||
159 | } while (0) | ||
160 | |||
161 | #define handle_abort(h) \ | ||
162 | do {\ | ||
163 | h->shift_reg = fast_abort[h->ffbit_shift - 1];\ | ||
164 | h->hdlc_bits1 = h->ffbit_shift - 2;\ | ||
165 | if (h->hdlc_bits1 < 0)\ | ||
166 | h->hdlc_bits1 = 0;\ | ||
167 | h->data_bits = h->ffbit_shift - 1;\ | ||
168 | h->state = HDLC_GET_DATA;\ | ||
169 | h->data_received = 0;\ | ||
170 | } while (0) | ||
171 | |||
141 | *count = slen; | 172 | *count = slen; |
142 | 173 | ||
143 | while(slen > 0){ | 174 | while (slen > 0) { |
144 | if(hdlc->bit_shift==0){ | 175 | if (hdlc->bit_shift == 0) { |
145 | hdlc->cbin = *src++; | 176 | /* the code is for bitreverse streams */ |
177 | if (hdlc->do_bitreverse == 0) | ||
178 | hdlc->cbin = bitrev8(*src++); | ||
179 | else | ||
180 | hdlc->cbin = *src++; | ||
146 | slen--; | 181 | slen--; |
147 | hdlc->bit_shift = 8; | 182 | hdlc->bit_shift = 8; |
148 | if(hdlc->do_adapt56){ | 183 | if (hdlc->do_adapt56) |
149 | hdlc->bit_shift --; | 184 | hdlc->bit_shift--; |
150 | } | ||
151 | } | 185 | } |
152 | 186 | ||
153 | switch(hdlc->state){ | 187 | switch (hdlc->state) { |
154 | case STOPPED: | 188 | case STOPPED: |
155 | return 0; | 189 | return 0; |
156 | case HDLC_FAST_IDLE: | 190 | case HDLC_FAST_IDLE: |
157 | if(hdlc->cbin == 0xff){ | 191 | if (hdlc->cbin == 0xff) { |
158 | hdlc->bit_shift = 0; | 192 | hdlc->bit_shift = 0; |
159 | break; | 193 | break; |
160 | } | 194 | } |
@@ -163,32 +197,30 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
163 | hdlc->bit_shift = 8; | 197 | hdlc->bit_shift = 8; |
164 | break; | 198 | break; |
165 | case HDLC_GET_FLAG_B0: | 199 | case HDLC_GET_FLAG_B0: |
166 | if(!(hdlc->cbin & 0x80)) { | 200 | if (!(hdlc->cbin & 0x80)) { |
167 | hdlc->state = HDLC_GETFLAG_B1A6; | 201 | hdlc->state = HDLC_GETFLAG_B1A6; |
168 | hdlc->hdlc_bits1 = 0; | 202 | hdlc->hdlc_bits1 = 0; |
169 | } else { | 203 | } else { |
170 | if(!hdlc->do_adapt56){ | 204 | if ((!hdlc->do_adapt56) && |
171 | if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) | 205 | (++hdlc->hdlc_bits1 >= 8) && |
206 | (hdlc->bit_shift == 1)) | ||
172 | hdlc->state = HDLC_FAST_IDLE; | 207 | hdlc->state = HDLC_FAST_IDLE; |
173 | } | ||
174 | } | 208 | } |
175 | hdlc->cbin<<=1; | 209 | hdlc->cbin <<= 1; |
176 | hdlc->bit_shift --; | 210 | hdlc->bit_shift--; |
177 | break; | 211 | break; |
178 | case HDLC_GETFLAG_B1A6: | 212 | case HDLC_GETFLAG_B1A6: |
179 | if(hdlc->cbin & 0x80){ | 213 | if (hdlc->cbin & 0x80) { |
180 | hdlc->hdlc_bits1++; | 214 | hdlc->hdlc_bits1++; |
181 | if(hdlc->hdlc_bits1==6){ | 215 | if (hdlc->hdlc_bits1 == 6) |
182 | hdlc->state = HDLC_GETFLAG_B7; | 216 | hdlc->state = HDLC_GETFLAG_B7; |
183 | } | 217 | } else |
184 | } else { | ||
185 | hdlc->hdlc_bits1 = 0; | 218 | hdlc->hdlc_bits1 = 0; |
186 | } | 219 | hdlc->cbin <<= 1; |
187 | hdlc->cbin<<=1; | 220 | hdlc->bit_shift--; |
188 | hdlc->bit_shift --; | ||
189 | break; | 221 | break; |
190 | case HDLC_GETFLAG_B7: | 222 | case HDLC_GETFLAG_B7: |
191 | if(hdlc->cbin & 0x80) { | 223 | if (hdlc->cbin & 0x80) { |
192 | hdlc->state = HDLC_GET_FLAG_B0; | 224 | hdlc->state = HDLC_GET_FLAG_B0; |
193 | } else { | 225 | } else { |
194 | hdlc->state = HDLC_GET_DATA; | 226 | hdlc->state = HDLC_GET_DATA; |
@@ -198,74 +230,55 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
198 | hdlc->data_bits = 0; | 230 | hdlc->data_bits = 0; |
199 | hdlc->data_received = 0; | 231 | hdlc->data_received = 0; |
200 | } | 232 | } |
201 | hdlc->cbin<<=1; | 233 | hdlc->cbin <<= 1; |
202 | hdlc->bit_shift --; | 234 | hdlc->bit_shift--; |
203 | break; | 235 | break; |
204 | case HDLC_GET_DATA: | 236 | case HDLC_GET_DATA: |
205 | if(hdlc->cbin & 0x80){ | 237 | if (hdlc->cbin & 0x80) { |
206 | hdlc->hdlc_bits1++; | 238 | hdlc->hdlc_bits1++; |
207 | switch(hdlc->hdlc_bits1){ | 239 | switch (hdlc->hdlc_bits1) { |
208 | case 6: | 240 | case 6: |
209 | break; | 241 | break; |
210 | case 7: | 242 | case 7: |
211 | if(hdlc->data_received) { | 243 | if (hdlc->data_received) |
212 | // bad frame | 244 | /* bad frame */ |
213 | status = -HDLC_FRAMING_ERROR; | 245 | status = -HDLC_FRAMING_ERROR; |
214 | } | 246 | if (!hdlc->do_adapt56) { |
215 | if(!hdlc->do_adapt56){ | 247 | if (hdlc->cbin == fast_abort |
216 | if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ | 248 | [hdlc->bit_shift + 1]) { |
217 | hdlc->state = HDLC_FAST_IDLE; | 249 | hdlc->state = |
218 | hdlc->bit_shift=1; | 250 | HDLC_FAST_IDLE; |
251 | hdlc->bit_shift = 1; | ||
219 | break; | 252 | break; |
220 | } | 253 | } |
221 | } else { | 254 | } else |
222 | hdlc->state = HDLC_GET_FLAG_B0; | 255 | hdlc->state = HDLC_GET_FLAG_B0; |
223 | } | ||
224 | break; | 256 | break; |
225 | default: | 257 | default: |
226 | hdlc->shift_reg>>=1; | 258 | hdlc->shift_reg >>= 1; |
227 | hdlc->shift_reg |= 0x80; | 259 | hdlc->shift_reg |= 0x80; |
228 | hdlc->data_bits++; | 260 | hdlc->data_bits++; |
229 | break; | 261 | break; |
230 | } | 262 | } |
231 | } else { | 263 | } else { |
232 | switch(hdlc->hdlc_bits1){ | 264 | switch (hdlc->hdlc_bits1) { |
233 | case 5: | 265 | case 5: |
234 | break; | 266 | break; |
235 | case 6: | 267 | case 6: |
236 | if(hdlc->data_received){ | 268 | if (hdlc->data_received) |
237 | if (hdlc->dstpos < 2) { | 269 | status = check_frame(hdlc); |
238 | status = -HDLC_FRAMING_ERROR; | ||
239 | } else if (hdlc->crc != 0xf0b8){ | ||
240 | // crc error | ||
241 | status = -HDLC_CRC_ERROR; | ||
242 | } else { | ||
243 | // remove CRC | ||
244 | hdlc->dstpos -= 2; | ||
245 | // good frame | ||
246 | status = hdlc->dstpos; | ||
247 | } | ||
248 | } | ||
249 | hdlc->crc = 0xffff; | 270 | hdlc->crc = 0xffff; |
250 | hdlc->shift_reg = 0; | 271 | hdlc->shift_reg = 0; |
251 | hdlc->data_bits = 0; | 272 | hdlc->data_bits = 0; |
252 | if(!hdlc->do_adapt56){ | 273 | if (!hdlc->do_adapt56) |
253 | if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ | 274 | handle_fast_flag(hdlc); |
254 | hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; | 275 | else { |
255 | hdlc->state = HDLC_FAST_FLAG; | ||
256 | hdlc->ffbit_shift = hdlc->bit_shift; | ||
257 | hdlc->bit_shift = 1; | ||
258 | } else { | ||
259 | hdlc->state = HDLC_GET_DATA; | ||
260 | hdlc->data_received = 0; | ||
261 | } | ||
262 | } else { | ||
263 | hdlc->state = HDLC_GET_DATA; | 276 | hdlc->state = HDLC_GET_DATA; |
264 | hdlc->data_received = 0; | 277 | hdlc->data_received = 0; |
265 | } | 278 | } |
266 | break; | 279 | break; |
267 | default: | 280 | default: |
268 | hdlc->shift_reg>>=1; | 281 | hdlc->shift_reg >>= 1; |
269 | hdlc->data_bits++; | 282 | hdlc->data_bits++; |
270 | break; | 283 | break; |
271 | } | 284 | } |
@@ -278,16 +291,17 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
278 | hdlc->bit_shift--; | 291 | hdlc->bit_shift--; |
279 | return status; | 292 | return status; |
280 | } | 293 | } |
281 | if(hdlc->data_bits==8){ | 294 | if (hdlc->data_bits == 8) { |
282 | hdlc->data_bits = 0; | 295 | hdlc->data_bits = 0; |
283 | hdlc->data_received = 1; | 296 | hdlc->data_received = 1; |
284 | hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); | 297 | hdlc->crc = crc_ccitt_byte(hdlc->crc, |
298 | hdlc->shift_reg); | ||
285 | 299 | ||
286 | // good byte received | 300 | /* good byte received */ |
287 | if (hdlc->dstpos < dsize) { | 301 | if (hdlc->dstpos < dsize) |
288 | dst[hdlc->dstpos++] = hdlc->shift_reg; | 302 | dst[hdlc->dstpos++] = hdlc->shift_reg; |
289 | } else { | 303 | else { |
290 | // frame too long | 304 | /* frame too long */ |
291 | status = -HDLC_LENGTH_ERROR; | 305 | status = -HDLC_LENGTH_ERROR; |
292 | hdlc->dstpos = 0; | 306 | hdlc->dstpos = 0; |
293 | } | 307 | } |
@@ -296,24 +310,18 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
296 | hdlc->bit_shift--; | 310 | hdlc->bit_shift--; |
297 | break; | 311 | break; |
298 | case HDLC_FAST_FLAG: | 312 | case HDLC_FAST_FLAG: |
299 | if(hdlc->cbin==hdlc->ffvalue){ | 313 | if (hdlc->cbin == hdlc->ffvalue) { |
300 | hdlc->bit_shift = 0; | 314 | hdlc->bit_shift = 0; |
301 | break; | 315 | break; |
302 | } else { | 316 | } else { |
303 | if(hdlc->cbin == 0xff){ | 317 | if (hdlc->cbin == 0xff) { |
304 | hdlc->state = HDLC_FAST_IDLE; | 318 | hdlc->state = HDLC_FAST_IDLE; |
305 | hdlc->bit_shift=0; | 319 | hdlc->bit_shift = 0; |
306 | } else if(hdlc->ffbit_shift==8){ | 320 | } else if (hdlc->ffbit_shift == 8) { |
307 | hdlc->state = HDLC_GETFLAG_B7; | 321 | hdlc->state = HDLC_GETFLAG_B7; |
308 | break; | 322 | break; |
309 | } else { | 323 | } else |
310 | hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; | 324 | handle_abort(hdlc); |
311 | hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; | ||
312 | if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; | ||
313 | hdlc->data_bits = hdlc->ffbit_shift-1; | ||
314 | hdlc->state = HDLC_GET_DATA; | ||
315 | hdlc->data_received = 0; | ||
316 | } | ||
317 | } | 325 | } |
318 | break; | 326 | break; |
319 | default: | 327 | default: |
@@ -323,7 +331,7 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
323 | *count -= slen; | 331 | *count -= slen; |
324 | return 0; | 332 | return 0; |
325 | } | 333 | } |
326 | 334 | EXPORT_SYMBOL(isdnhdlc_decode); | |
327 | /* | 335 | /* |
328 | isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. | 336 | isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. |
329 | 337 | ||
@@ -343,59 +351,70 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
343 | dsize - destination buffer size | 351 | dsize - destination buffer size |
344 | returns - number of encoded bytes in the destination buffer | 352 | returns - number of encoded bytes in the destination buffer |
345 | */ | 353 | */ |
346 | int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | 354 | int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, |
347 | unsigned short slen, int *count, | 355 | int *count, u8 *dst, int dsize) |
348 | unsigned char *dst, int dsize) | ||
349 | { | 356 | { |
350 | static const unsigned char xfast_flag_value[] = { | 357 | static const unsigned char xfast_flag_value[] = { |
351 | 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e | 358 | 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e |
352 | }; | 359 | }; |
353 | 360 | ||
354 | int len = 0; | 361 | int len = 0; |
355 | 362 | ||
356 | *count = slen; | 363 | *count = slen; |
357 | 364 | ||
365 | /* special handling for one byte frames */ | ||
366 | if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) | ||
367 | hdlc->state = HDLC_SENDFLAG_ONE; | ||
358 | while (dsize > 0) { | 368 | while (dsize > 0) { |
359 | if(hdlc->bit_shift==0){ | 369 | if (hdlc->bit_shift == 0) { |
360 | if(slen && !hdlc->do_closing){ | 370 | if (slen && !hdlc->do_closing) { |
361 | hdlc->shift_reg = *src++; | 371 | hdlc->shift_reg = *src++; |
362 | slen--; | 372 | slen--; |
363 | if (slen == 0) | 373 | if (slen == 0) |
364 | hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ | 374 | /* closing sequence, CRC + flag(s) */ |
375 | hdlc->do_closing = 1; | ||
365 | hdlc->bit_shift = 8; | 376 | hdlc->bit_shift = 8; |
366 | } else { | 377 | } else { |
367 | if(hdlc->state == HDLC_SEND_DATA){ | 378 | if (hdlc->state == HDLC_SEND_DATA) { |
368 | if(hdlc->data_received){ | 379 | if (hdlc->data_received) { |
369 | hdlc->state = HDLC_SEND_CRC1; | 380 | hdlc->state = HDLC_SEND_CRC1; |
370 | hdlc->crc ^= 0xffff; | 381 | hdlc->crc ^= 0xffff; |
371 | hdlc->bit_shift = 8; | 382 | hdlc->bit_shift = 8; |
372 | hdlc->shift_reg = hdlc->crc & 0xff; | 383 | hdlc->shift_reg = |
373 | } else if(!hdlc->do_adapt56){ | 384 | hdlc->crc & 0xff; |
374 | hdlc->state = HDLC_SEND_FAST_FLAG; | 385 | } else if (!hdlc->do_adapt56) |
375 | } else { | 386 | hdlc->state = |
376 | hdlc->state = HDLC_SENDFLAG_B0; | 387 | HDLC_SEND_FAST_FLAG; |
377 | } | 388 | else |
389 | hdlc->state = | ||
390 | HDLC_SENDFLAG_B0; | ||
378 | } | 391 | } |
379 | 392 | ||
380 | } | 393 | } |
381 | } | 394 | } |
382 | 395 | ||
383 | switch(hdlc->state){ | 396 | switch (hdlc->state) { |
384 | case STOPPED: | 397 | case STOPPED: |
385 | while (dsize--) | 398 | while (dsize--) |
386 | *dst++ = 0xff; | 399 | *dst++ = 0xff; |
387 | |||
388 | return dsize; | 400 | return dsize; |
389 | case HDLC_SEND_FAST_FLAG: | 401 | case HDLC_SEND_FAST_FLAG: |
390 | hdlc->do_closing = 0; | 402 | hdlc->do_closing = 0; |
391 | if(slen == 0){ | 403 | if (slen == 0) { |
392 | *dst++ = hdlc->ffvalue; | 404 | /* the code is for bitreverse streams */ |
405 | if (hdlc->do_bitreverse == 0) | ||
406 | *dst++ = bitrev8(hdlc->ffvalue); | ||
407 | else | ||
408 | *dst++ = hdlc->ffvalue; | ||
393 | len++; | 409 | len++; |
394 | dsize--; | 410 | dsize--; |
395 | break; | 411 | break; |
396 | } | 412 | } |
397 | if(hdlc->bit_shift==8){ | 413 | /* fall through */ |
398 | hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); | 414 | case HDLC_SENDFLAG_ONE: |
415 | if (hdlc->bit_shift == 8) { | ||
416 | hdlc->cbin = hdlc->ffvalue >> | ||
417 | (8 - hdlc->data_bits); | ||
399 | hdlc->state = HDLC_SEND_DATA; | 418 | hdlc->state = HDLC_SEND_DATA; |
400 | hdlc->crc = 0xffff; | 419 | hdlc->crc = 0xffff; |
401 | hdlc->hdlc_bits1 = 0; | 420 | hdlc->hdlc_bits1 = 0; |
@@ -413,17 +432,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
413 | hdlc->cbin <<= 1; | 432 | hdlc->cbin <<= 1; |
414 | hdlc->data_bits++; | 433 | hdlc->data_bits++; |
415 | hdlc->cbin++; | 434 | hdlc->cbin++; |
416 | if(++hdlc->hdlc_bits1 == 6) | 435 | if (++hdlc->hdlc_bits1 == 6) |
417 | hdlc->state = HDLC_SENDFLAG_B7; | 436 | hdlc->state = HDLC_SENDFLAG_B7; |
418 | break; | 437 | break; |
419 | case HDLC_SENDFLAG_B7: | 438 | case HDLC_SENDFLAG_B7: |
420 | hdlc->cbin <<= 1; | 439 | hdlc->cbin <<= 1; |
421 | hdlc->data_bits++; | 440 | hdlc->data_bits++; |
422 | if(slen == 0){ | 441 | if (slen == 0) { |
423 | hdlc->state = HDLC_SENDFLAG_B0; | 442 | hdlc->state = HDLC_SENDFLAG_B0; |
424 | break; | 443 | break; |
425 | } | 444 | } |
426 | if(hdlc->bit_shift==8){ | 445 | if (hdlc->bit_shift == 8) { |
427 | hdlc->state = HDLC_SEND_DATA; | 446 | hdlc->state = HDLC_SEND_DATA; |
428 | hdlc->crc = 0xffff; | 447 | hdlc->crc = 0xffff; |
429 | hdlc->hdlc_bits1 = 0; | 448 | hdlc->hdlc_bits1 = 0; |
@@ -432,7 +451,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
432 | break; | 451 | break; |
433 | case HDLC_SEND_FIRST_FLAG: | 452 | case HDLC_SEND_FIRST_FLAG: |
434 | hdlc->data_received = 1; | 453 | hdlc->data_received = 1; |
435 | if(hdlc->data_bits==8){ | 454 | if (hdlc->data_bits == 8) { |
436 | hdlc->state = HDLC_SEND_DATA; | 455 | hdlc->state = HDLC_SEND_DATA; |
437 | hdlc->crc = 0xffff; | 456 | hdlc->crc = 0xffff; |
438 | hdlc->hdlc_bits1 = 0; | 457 | hdlc->hdlc_bits1 = 0; |
@@ -440,11 +459,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
440 | } | 459 | } |
441 | hdlc->cbin <<= 1; | 460 | hdlc->cbin <<= 1; |
442 | hdlc->data_bits++; | 461 | hdlc->data_bits++; |
443 | if(hdlc->shift_reg & 0x01) | 462 | if (hdlc->shift_reg & 0x01) |
444 | hdlc->cbin++; | 463 | hdlc->cbin++; |
445 | hdlc->shift_reg >>= 1; | 464 | hdlc->shift_reg >>= 1; |
446 | hdlc->bit_shift--; | 465 | hdlc->bit_shift--; |
447 | if(hdlc->bit_shift==0){ | 466 | if (hdlc->bit_shift == 0) { |
448 | hdlc->state = HDLC_SEND_DATA; | 467 | hdlc->state = HDLC_SEND_DATA; |
449 | hdlc->crc = 0xffff; | 468 | hdlc->crc = 0xffff; |
450 | hdlc->hdlc_bits1 = 0; | 469 | hdlc->hdlc_bits1 = 0; |
@@ -453,14 +472,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
453 | case HDLC_SEND_DATA: | 472 | case HDLC_SEND_DATA: |
454 | hdlc->cbin <<= 1; | 473 | hdlc->cbin <<= 1; |
455 | hdlc->data_bits++; | 474 | hdlc->data_bits++; |
456 | if(hdlc->hdlc_bits1 == 5){ | 475 | if (hdlc->hdlc_bits1 == 5) { |
457 | hdlc->hdlc_bits1 = 0; | 476 | hdlc->hdlc_bits1 = 0; |
458 | break; | 477 | break; |
459 | } | 478 | } |
460 | if(hdlc->bit_shift==8){ | 479 | if (hdlc->bit_shift == 8) |
461 | hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); | 480 | hdlc->crc = crc_ccitt_byte(hdlc->crc, |
462 | } | 481 | hdlc->shift_reg); |
463 | if(hdlc->shift_reg & 0x01){ | 482 | if (hdlc->shift_reg & 0x01) { |
464 | hdlc->hdlc_bits1++; | 483 | hdlc->hdlc_bits1++; |
465 | hdlc->cbin++; | 484 | hdlc->cbin++; |
466 | hdlc->shift_reg >>= 1; | 485 | hdlc->shift_reg >>= 1; |
@@ -474,11 +493,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
474 | case HDLC_SEND_CRC1: | 493 | case HDLC_SEND_CRC1: |
475 | hdlc->cbin <<= 1; | 494 | hdlc->cbin <<= 1; |
476 | hdlc->data_bits++; | 495 | hdlc->data_bits++; |
477 | if(hdlc->hdlc_bits1 == 5){ | 496 | if (hdlc->hdlc_bits1 == 5) { |
478 | hdlc->hdlc_bits1 = 0; | 497 | hdlc->hdlc_bits1 = 0; |
479 | break; | 498 | break; |
480 | } | 499 | } |
481 | if(hdlc->shift_reg & 0x01){ | 500 | if (hdlc->shift_reg & 0x01) { |
482 | hdlc->hdlc_bits1++; | 501 | hdlc->hdlc_bits1++; |
483 | hdlc->cbin++; | 502 | hdlc->cbin++; |
484 | hdlc->shift_reg >>= 1; | 503 | hdlc->shift_reg >>= 1; |
@@ -488,7 +507,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
488 | hdlc->shift_reg >>= 1; | 507 | hdlc->shift_reg >>= 1; |
489 | hdlc->bit_shift--; | 508 | hdlc->bit_shift--; |
490 | } | 509 | } |
491 | if(hdlc->bit_shift==0){ | 510 | if (hdlc->bit_shift == 0) { |
492 | hdlc->shift_reg = (hdlc->crc >> 8); | 511 | hdlc->shift_reg = (hdlc->crc >> 8); |
493 | hdlc->state = HDLC_SEND_CRC2; | 512 | hdlc->state = HDLC_SEND_CRC2; |
494 | hdlc->bit_shift = 8; | 513 | hdlc->bit_shift = 8; |
@@ -497,11 +516,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
497 | case HDLC_SEND_CRC2: | 516 | case HDLC_SEND_CRC2: |
498 | hdlc->cbin <<= 1; | 517 | hdlc->cbin <<= 1; |
499 | hdlc->data_bits++; | 518 | hdlc->data_bits++; |
500 | if(hdlc->hdlc_bits1 == 5){ | 519 | if (hdlc->hdlc_bits1 == 5) { |
501 | hdlc->hdlc_bits1 = 0; | 520 | hdlc->hdlc_bits1 = 0; |
502 | break; | 521 | break; |
503 | } | 522 | } |
504 | if(hdlc->shift_reg & 0x01){ | 523 | if (hdlc->shift_reg & 0x01) { |
505 | hdlc->hdlc_bits1++; | 524 | hdlc->hdlc_bits1++; |
506 | hdlc->cbin++; | 525 | hdlc->cbin++; |
507 | hdlc->shift_reg >>= 1; | 526 | hdlc->shift_reg >>= 1; |
@@ -511,7 +530,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
511 | hdlc->shift_reg >>= 1; | 530 | hdlc->shift_reg >>= 1; |
512 | hdlc->bit_shift--; | 531 | hdlc->bit_shift--; |
513 | } | 532 | } |
514 | if(hdlc->bit_shift==0){ | 533 | if (hdlc->bit_shift == 0) { |
515 | hdlc->shift_reg = 0x7e; | 534 | hdlc->shift_reg = 0x7e; |
516 | hdlc->state = HDLC_SEND_CLOSING_FLAG; | 535 | hdlc->state = HDLC_SEND_CLOSING_FLAG; |
517 | hdlc->bit_shift = 8; | 536 | hdlc->bit_shift = 8; |
@@ -520,33 +539,36 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
520 | case HDLC_SEND_CLOSING_FLAG: | 539 | case HDLC_SEND_CLOSING_FLAG: |
521 | hdlc->cbin <<= 1; | 540 | hdlc->cbin <<= 1; |
522 | hdlc->data_bits++; | 541 | hdlc->data_bits++; |
523 | if(hdlc->hdlc_bits1 == 5){ | 542 | if (hdlc->hdlc_bits1 == 5) { |
524 | hdlc->hdlc_bits1 = 0; | 543 | hdlc->hdlc_bits1 = 0; |
525 | break; | 544 | break; |
526 | } | 545 | } |
527 | if(hdlc->shift_reg & 0x01){ | 546 | if (hdlc->shift_reg & 0x01) |
528 | hdlc->cbin++; | 547 | hdlc->cbin++; |
529 | } | ||
530 | hdlc->shift_reg >>= 1; | 548 | hdlc->shift_reg >>= 1; |
531 | hdlc->bit_shift--; | 549 | hdlc->bit_shift--; |
532 | if(hdlc->bit_shift==0){ | 550 | if (hdlc->bit_shift == 0) { |
533 | hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; | 551 | hdlc->ffvalue = |
534 | if(hdlc->dchannel){ | 552 | xfast_flag_value[hdlc->data_bits]; |
553 | if (hdlc->dchannel) { | ||
535 | hdlc->ffvalue = 0x7e; | 554 | hdlc->ffvalue = 0x7e; |
536 | hdlc->state = HDLC_SEND_IDLE1; | 555 | hdlc->state = HDLC_SEND_IDLE1; |
537 | hdlc->bit_shift = 8-hdlc->data_bits; | 556 | hdlc->bit_shift = 8-hdlc->data_bits; |
538 | if(hdlc->bit_shift==0) | 557 | if (hdlc->bit_shift == 0) |
539 | hdlc->state = HDLC_SEND_FAST_IDLE; | 558 | hdlc->state = |
559 | HDLC_SEND_FAST_IDLE; | ||
540 | } else { | 560 | } else { |
541 | if(!hdlc->do_adapt56){ | 561 | if (!hdlc->do_adapt56) { |
542 | hdlc->state = HDLC_SEND_FAST_FLAG; | 562 | hdlc->state = |
563 | HDLC_SEND_FAST_FLAG; | ||
543 | hdlc->data_received = 0; | 564 | hdlc->data_received = 0; |
544 | } else { | 565 | } else { |
545 | hdlc->state = HDLC_SENDFLAG_B0; | 566 | hdlc->state = HDLC_SENDFLAG_B0; |
546 | hdlc->data_received = 0; | 567 | hdlc->data_received = 0; |
547 | } | 568 | } |
548 | // Finished with this frame, send flags | 569 | /* Finished this frame, send flags */ |
549 | if (dsize > 1) dsize = 1; | 570 | if (dsize > 1) |
571 | dsize = 1; | ||
550 | } | 572 | } |
551 | } | 573 | } |
552 | break; | 574 | break; |
@@ -556,7 +578,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
556 | hdlc->cbin++; | 578 | hdlc->cbin++; |
557 | hdlc->data_bits++; | 579 | hdlc->data_bits++; |
558 | hdlc->bit_shift--; | 580 | hdlc->bit_shift--; |
559 | if(hdlc->bit_shift==0){ | 581 | if (hdlc->bit_shift == 0) { |
560 | hdlc->state = HDLC_SEND_FAST_IDLE; | 582 | hdlc->state = HDLC_SEND_FAST_IDLE; |
561 | hdlc->bit_shift = 0; | 583 | hdlc->bit_shift = 0; |
562 | } | 584 | } |
@@ -565,12 +587,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
565 | hdlc->do_closing = 0; | 587 | hdlc->do_closing = 0; |
566 | hdlc->cbin = 0xff; | 588 | hdlc->cbin = 0xff; |
567 | hdlc->data_bits = 8; | 589 | hdlc->data_bits = 8; |
568 | if(hdlc->bit_shift == 8){ | 590 | if (hdlc->bit_shift == 8) { |
569 | hdlc->cbin = 0x7e; | 591 | hdlc->cbin = 0x7e; |
570 | hdlc->state = HDLC_SEND_FIRST_FLAG; | 592 | hdlc->state = HDLC_SEND_FIRST_FLAG; |
571 | } else { | 593 | } else { |
572 | *dst++ = hdlc->cbin; | 594 | /* the code is for bitreverse streams */ |
573 | hdlc->bit_shift = hdlc->data_bits = 0; | 595 | if (hdlc->do_bitreverse == 0) |
596 | *dst++ = bitrev8(hdlc->cbin); | ||
597 | else | ||
598 | *dst++ = hdlc->cbin; | ||
599 | hdlc->bit_shift = 0; | ||
600 | hdlc->data_bits = 0; | ||
574 | len++; | 601 | len++; |
575 | dsize = 0; | 602 | dsize = 0; |
576 | } | 603 | } |
@@ -578,15 +605,19 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
578 | default: | 605 | default: |
579 | break; | 606 | break; |
580 | } | 607 | } |
581 | if(hdlc->do_adapt56){ | 608 | if (hdlc->do_adapt56) { |
582 | if(hdlc->data_bits==7){ | 609 | if (hdlc->data_bits == 7) { |
583 | hdlc->cbin <<= 1; | 610 | hdlc->cbin <<= 1; |
584 | hdlc->cbin++; | 611 | hdlc->cbin++; |
585 | hdlc->data_bits++; | 612 | hdlc->data_bits++; |
586 | } | 613 | } |
587 | } | 614 | } |
588 | if(hdlc->data_bits==8){ | 615 | if (hdlc->data_bits == 8) { |
589 | *dst++ = hdlc->cbin; | 616 | /* the code is for bitreverse streams */ |
617 | if (hdlc->do_bitreverse == 0) | ||
618 | *dst++ = bitrev8(hdlc->cbin); | ||
619 | else | ||
620 | *dst++ = hdlc->cbin; | ||
590 | hdlc->data_bits = 0; | 621 | hdlc->data_bits = 0; |
591 | len++; | 622 | len++; |
592 | dsize--; | 623 | dsize--; |
@@ -596,8 +627,4 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, | |||
596 | 627 | ||
597 | return len; | 628 | return len; |
598 | } | 629 | } |
599 | |||
600 | EXPORT_SYMBOL(isdnhdlc_rcv_init); | ||
601 | EXPORT_SYMBOL(isdnhdlc_decode); | ||
602 | EXPORT_SYMBOL(isdnhdlc_out_init); | ||
603 | EXPORT_SYMBOL(isdnhdlc_encode); | 630 | EXPORT_SYMBOL(isdnhdlc_encode); |
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 0481a0cdf6db..e8049be552aa 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c | |||
@@ -114,13 +114,14 @@ mISDN_freedchannel(struct dchannel *ch) | |||
114 | } | 114 | } |
115 | EXPORT_SYMBOL(mISDN_freedchannel); | 115 | EXPORT_SYMBOL(mISDN_freedchannel); |
116 | 116 | ||
117 | int | 117 | void |
118 | mISDN_freebchannel(struct bchannel *ch) | 118 | mISDN_clear_bchannel(struct bchannel *ch) |
119 | { | 119 | { |
120 | if (ch->tx_skb) { | 120 | if (ch->tx_skb) { |
121 | dev_kfree_skb(ch->tx_skb); | 121 | dev_kfree_skb(ch->tx_skb); |
122 | ch->tx_skb = NULL; | 122 | ch->tx_skb = NULL; |
123 | } | 123 | } |
124 | ch->tx_idx = 0; | ||
124 | if (ch->rx_skb) { | 125 | if (ch->rx_skb) { |
125 | dev_kfree_skb(ch->rx_skb); | 126 | dev_kfree_skb(ch->rx_skb); |
126 | ch->rx_skb = NULL; | 127 | ch->rx_skb = NULL; |
@@ -129,6 +130,16 @@ mISDN_freebchannel(struct bchannel *ch) | |||
129 | dev_kfree_skb(ch->next_skb); | 130 | dev_kfree_skb(ch->next_skb); |
130 | ch->next_skb = NULL; | 131 | ch->next_skb = NULL; |
131 | } | 132 | } |
133 | test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); | ||
134 | test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); | ||
135 | test_and_clear_bit(FLG_ACTIVE, &ch->Flags); | ||
136 | } | ||
137 | EXPORT_SYMBOL(mISDN_clear_bchannel); | ||
138 | |||
139 | int | ||
140 | mISDN_freebchannel(struct bchannel *ch) | ||
141 | { | ||
142 | mISDN_clear_bchannel(ch); | ||
132 | skb_queue_purge(&ch->rqueue); | 143 | skb_queue_purge(&ch->rqueue); |
133 | ch->rcount = 0; | 144 | ch->rcount = 0; |
134 | flush_scheduled_work(); | 145 | flush_scheduled_work(); |
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 9c2589e986d6..e17f0044e0b6 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c | |||
@@ -1832,8 +1832,6 @@ static struct FsmNode L2FnList[] = | |||
1832 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, | 1832 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, |
1833 | }; | 1833 | }; |
1834 | 1834 | ||
1835 | #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) | ||
1836 | |||
1837 | static int | 1835 | static int |
1838 | ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) | 1836 | ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) |
1839 | { | 1837 | { |