diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-26 23:19:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-26 23:19:41 -0400 |
commit | 5c7c204aeca51ccfad63caab4fcdc5d8026c0fd8 (patch) | |
tree | 4bfd5f4455b706c9ba86a8925bf367f437d16336 | |
parent | 228428428138e231a155464239880201e5cc8b44 (diff) | |
parent | 3712b42d4b1bec29a4232a6673bf2e6dcc5faa68 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/ISDN-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/ISDN-2.6:
Add layer1 over IP support
Add mISDN HFC multiport driver
Add mISDN HFC PCI driver
Add mISDN DSP
Add mISDN core files
Define AF_ISDN and PF_ISDN
Add mISDN driver
45 files changed, 24632 insertions, 2 deletions
diff --git a/Documentation/isdn/README.mISDN b/Documentation/isdn/README.mISDN new file mode 100644 index 000000000000..cd8bf920e77b --- /dev/null +++ b/Documentation/isdn/README.mISDN | |||
@@ -0,0 +1,6 @@ | |||
1 | mISDN is a new modular ISDN driver, in the long term it should replace | ||
2 | the old I4L driver architecture for passiv ISDN cards. | ||
3 | It was designed to allow a broad range of applications and interfaces | ||
4 | but only have the basic function in kernel, the interface to the user | ||
5 | space is based on sockets with a own address family AF_ISDN. | ||
6 | |||
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 66f946aa30b3..3d113c6e4a70 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | menuconfig ISDN | 5 | menuconfig ISDN |
6 | tristate "ISDN support" | 6 | bool "ISDN support" |
7 | depends on NET | 7 | depends on NET |
8 | depends on !S390 | 8 | depends on !S390 |
9 | ---help--- | 9 | ---help--- |
@@ -21,6 +21,8 @@ menuconfig ISDN | |||
21 | 21 | ||
22 | if ISDN | 22 | if ISDN |
23 | 23 | ||
24 | source "drivers/isdn/mISDN/Kconfig" | ||
25 | |||
24 | menuconfig ISDN_I4L | 26 | menuconfig ISDN_I4L |
25 | tristate "Old ISDN4Linux (deprecated)" | 27 | tristate "Old ISDN4Linux (deprecated)" |
26 | ---help--- | 28 | ---help--- |
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 988142c30a6d..8380a4568d11 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_ISDN_I4L) += i4l/ | 5 | obj-$(CONFIG_ISDN_I4L) += i4l/ |
6 | obj-$(CONFIG_ISDN_CAPI) += capi/ | 6 | obj-$(CONFIG_ISDN_CAPI) += capi/ |
7 | obj-$(CONFIG_MISDN) += mISDN/ | ||
7 | obj-$(CONFIG_ISDN_CAPI) += hardware/ | 8 | obj-$(CONFIG_ISDN_CAPI) += hardware/ |
8 | obj-$(CONFIG_ISDN_DIVERSION) += divert/ | 9 | obj-$(CONFIG_ISDN_DIVERSION) += divert/ |
9 | obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ | 10 | obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ |
diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile index 11c8a183948c..a5d8fce4c4c4 100644 --- a/drivers/isdn/hardware/Makefile +++ b/drivers/isdn/hardware/Makefile | |||
@@ -4,3 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_CAPI_AVM) += avm/ | 5 | obj-$(CONFIG_CAPI_AVM) += avm/ |
6 | obj-$(CONFIG_CAPI_EICON) += eicon/ | 6 | obj-$(CONFIG_CAPI_EICON) += eicon/ |
7 | obj-$(CONFIG_MISDN) += mISDN/ | ||
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig new file mode 100644 index 000000000000..14793480c453 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/Kconfig | |||
@@ -0,0 +1,25 @@ | |||
1 | # | ||
2 | # Hardware for mISDN | ||
3 | # | ||
4 | comment "mISDN hardware drivers" | ||
5 | |||
6 | config MISDN_HFCPCI | ||
7 | tristate "Support for HFC PCI cards" | ||
8 | depends on MISDN | ||
9 | depends on PCI | ||
10 | help | ||
11 | Enable support for cards with Cologne Chip AG's | ||
12 | HFC PCI chip. | ||
13 | |||
14 | config MISDN_HFCMULTI | ||
15 | tristate "Support for HFC multiport cards (HFC-4S/8S/E1)" | ||
16 | depends on PCI | ||
17 | depends on MISDN | ||
18 | help | ||
19 | Enable support for cards with Cologne Chip AG's HFC multiport | ||
20 | chip. There are three types of chips that are quite similar, | ||
21 | but the interface is different: | ||
22 | * HFC-4S (4 S/T interfaces on one chip) | ||
23 | * HFC-8S (8 S/T interfaces on one chip) | ||
24 | * HFC-E1 (E1 interface for 2Mbit ISDN) | ||
25 | |||
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile new file mode 100644 index 000000000000..1e7ca5332ad7 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the modular ISDN hardware drivers | ||
3 | # | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o | ||
7 | obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o | ||
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h new file mode 100644 index 000000000000..a33d87afc843 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h | |||
@@ -0,0 +1,1204 @@ | |||
1 | /* | ||
2 | * see notice in hfc_multi.c | ||
3 | */ | ||
4 | |||
5 | extern void ztdummy_extern_interrupt(void); | ||
6 | extern void ztdummy_register_interrupt(void); | ||
7 | extern int ztdummy_unregister_interrupt(void); | ||
8 | |||
9 | #define DEBUG_HFCMULTI_FIFO 0x00010000 | ||
10 | #define DEBUG_HFCMULTI_CRC 0x00020000 | ||
11 | #define DEBUG_HFCMULTI_INIT 0x00040000 | ||
12 | #define DEBUG_HFCMULTI_PLXSD 0x00080000 | ||
13 | #define DEBUG_HFCMULTI_MODE 0x00100000 | ||
14 | #define DEBUG_HFCMULTI_MSG 0x00200000 | ||
15 | #define DEBUG_HFCMULTI_STATE 0x00400000 | ||
16 | #define DEBUG_HFCMULTI_SYNC 0x01000000 | ||
17 | #define DEBUG_HFCMULTI_DTMF 0x02000000 | ||
18 | #define DEBUG_HFCMULTI_LOCK 0x80000000 | ||
19 | |||
20 | #define PCI_ENA_REGIO 0x01 | ||
21 | #define PCI_ENA_MEMIO 0x02 | ||
22 | |||
23 | /* | ||
24 | * NOTE: some registers are assigned multiple times due to different modes | ||
25 | * also registers are assigned differen for HFC-4s/8s and HFC-E1 | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | #define MAX_FRAME_SIZE 2048 | ||
30 | */ | ||
31 | |||
32 | struct hfc_chan { | ||
33 | struct dchannel *dch; /* link if channel is a D-channel */ | ||
34 | struct bchannel *bch; /* link if channel is a B-channel */ | ||
35 | int port; /* the interface port this */ | ||
36 | /* channel is associated with */ | ||
37 | int nt_timer; /* -1 if off, 0 if elapsed, >0 if running */ | ||
38 | int los, ais, slip_tx, slip_rx, rdi; /* current alarms */ | ||
39 | int jitter; | ||
40 | u_long cfg; /* port configuration */ | ||
41 | int sync; /* sync state (used by E1) */ | ||
42 | u_int protocol; /* current protocol */ | ||
43 | int slot_tx; /* current pcm slot */ | ||
44 | int bank_tx; /* current pcm bank */ | ||
45 | int slot_rx; | ||
46 | int bank_rx; | ||
47 | int conf; /* conference setting of TX slot */ | ||
48 | int txpending; /* if there is currently data in */ | ||
49 | /* the FIFO 0=no, 1=yes, 2=splloop */ | ||
50 | int rx_off; /* set to turn fifo receive off */ | ||
51 | int coeff_count; /* curren coeff block */ | ||
52 | s32 *coeff; /* memory pointer to 8 coeff blocks */ | ||
53 | }; | ||
54 | |||
55 | |||
56 | struct hfcm_hw { | ||
57 | u_char r_ctrl; | ||
58 | u_char r_irq_ctrl; | ||
59 | u_char r_cirm; | ||
60 | u_char r_ram_sz; | ||
61 | u_char r_pcm_md0; | ||
62 | u_char r_irqmsk_misc; | ||
63 | u_char r_dtmf; | ||
64 | u_char r_st_sync; | ||
65 | u_char r_sci_msk; | ||
66 | u_char r_tx0, r_tx1; | ||
67 | u_char a_st_ctrl0[8]; | ||
68 | timer_t timer; | ||
69 | }; | ||
70 | |||
71 | |||
72 | /* for each stack these flags are used (cfg) */ | ||
73 | #define HFC_CFG_NONCAP_TX 1 /* S/T TX interface has less capacity */ | ||
74 | #define HFC_CFG_DIS_ECHANNEL 2 /* disable E-channel processing */ | ||
75 | #define HFC_CFG_REG_ECHANNEL 3 /* register E-channel */ | ||
76 | #define HFC_CFG_OPTICAL 4 /* the E1 interface is optical */ | ||
77 | #define HFC_CFG_REPORT_LOS 5 /* the card should report loss of signal */ | ||
78 | #define HFC_CFG_REPORT_AIS 6 /* the card should report alarm ind. sign. */ | ||
79 | #define HFC_CFG_REPORT_SLIP 7 /* the card should report bit slips */ | ||
80 | #define HFC_CFG_REPORT_RDI 8 /* the card should report remote alarm */ | ||
81 | #define HFC_CFG_DTMF 9 /* enable DTMF-detection */ | ||
82 | #define HFC_CFG_CRC4 10 /* disable CRC-4 Multiframe mode, */ | ||
83 | /* use double frame instead. */ | ||
84 | |||
85 | #define HFC_CHIP_EXRAM_128 0 /* external ram 128k */ | ||
86 | #define HFC_CHIP_EXRAM_512 1 /* external ram 256k */ | ||
87 | #define HFC_CHIP_REVISION0 2 /* old fifo handling */ | ||
88 | #define HFC_CHIP_PCM_SLAVE 3 /* PCM is slave */ | ||
89 | #define HFC_CHIP_PCM_MASTER 4 /* PCM is master */ | ||
90 | #define HFC_CHIP_RX_SYNC 5 /* disable pll sync for pcm */ | ||
91 | #define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */ | ||
92 | #define HFC_CHIP_ULAW 7 /* ULAW mode */ | ||
93 | #define HFC_CHIP_CLOCK2 8 /* double clock mode */ | ||
94 | #define HFC_CHIP_E1CLOCK_GET 9 /* always get clock from E1 interface */ | ||
95 | #define HFC_CHIP_E1CLOCK_PUT 10 /* always put clock from E1 interface */ | ||
96 | #define HFC_CHIP_WATCHDOG 11 /* whether we should send signals */ | ||
97 | /* to the watchdog */ | ||
98 | #define HFC_CHIP_B410P 12 /* whether we have a b410p with echocan in */ | ||
99 | /* hw */ | ||
100 | #define HFC_CHIP_PLXSD 13 /* whether we have a Speech-Design PLX */ | ||
101 | |||
102 | #define HFC_IO_MODE_PCIMEM 0x00 /* normal memory mapped IO */ | ||
103 | #define HFC_IO_MODE_REGIO 0x01 /* PCI io access */ | ||
104 | #define HFC_IO_MODE_PLXSD 0x02 /* access HFC via PLX9030 */ | ||
105 | |||
106 | /* table entry in the PCI devices list */ | ||
107 | struct hm_map { | ||
108 | char *vendor_name; | ||
109 | char *card_name; | ||
110 | int type; | ||
111 | int ports; | ||
112 | int clock2; | ||
113 | int leds; | ||
114 | int opticalsupport; | ||
115 | int dip_type; | ||
116 | int io_mode; | ||
117 | }; | ||
118 | |||
119 | struct hfc_multi { | ||
120 | struct list_head list; | ||
121 | struct hm_map *mtyp; | ||
122 | int id; | ||
123 | int pcm; /* id of pcm bus */ | ||
124 | int type; | ||
125 | int ports; | ||
126 | |||
127 | u_int irq; /* irq used by card */ | ||
128 | u_int irqcnt; | ||
129 | struct pci_dev *pci_dev; | ||
130 | int io_mode; /* selects mode */ | ||
131 | #ifdef HFC_REGISTER_DEBUG | ||
132 | void (*HFC_outb)(struct hfc_multi *hc, u_char reg, | ||
133 | u_char val, const char *function, int line); | ||
134 | void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg, | ||
135 | u_char val, const char *function, int line); | ||
136 | u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg, | ||
137 | const char *function, int line); | ||
138 | u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg, | ||
139 | const char *function, int line); | ||
140 | u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg, | ||
141 | const char *function, int line); | ||
142 | u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg, | ||
143 | const char *function, int line); | ||
144 | void (*HFC_wait)(struct hfc_multi *hc, | ||
145 | const char *function, int line); | ||
146 | void (*HFC_wait_nodebug)(struct hfc_multi *hc, | ||
147 | const char *function, int line); | ||
148 | #else | ||
149 | void (*HFC_outb)(struct hfc_multi *hc, u_char reg, | ||
150 | u_char val); | ||
151 | void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg, | ||
152 | u_char val); | ||
153 | u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg); | ||
154 | u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg); | ||
155 | u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg); | ||
156 | u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg); | ||
157 | void (*HFC_wait)(struct hfc_multi *hc); | ||
158 | void (*HFC_wait_nodebug)(struct hfc_multi *hc); | ||
159 | #endif | ||
160 | void (*read_fifo)(struct hfc_multi *hc, u_char *data, | ||
161 | int len); | ||
162 | void (*write_fifo)(struct hfc_multi *hc, u_char *data, | ||
163 | int len); | ||
164 | u_long pci_origmembase, plx_origmembase, dsp_origmembase; | ||
165 | u_char *pci_membase; /* PCI memory (MUST BE BYTE POINTER) */ | ||
166 | u_char *plx_membase; /* PLX memory */ | ||
167 | u_char *dsp_membase; /* DSP on PLX */ | ||
168 | u_long pci_iobase; /* PCI IO */ | ||
169 | struct hfcm_hw hw; /* remember data of write-only-registers */ | ||
170 | |||
171 | u_long chip; /* chip configuration */ | ||
172 | int masterclk; /* port that provides master clock -1=off */ | ||
173 | int dtmf; /* flag that dtmf is currently in process */ | ||
174 | int Flen; /* F-buffer size */ | ||
175 | int Zlen; /* Z-buffer size (must be int for calculation)*/ | ||
176 | int max_trans; /* maximum transparent fifo fill */ | ||
177 | int Zmin; /* Z-buffer offset */ | ||
178 | int DTMFbase; /* base address of DTMF coefficients */ | ||
179 | |||
180 | u_int slots; /* number of PCM slots */ | ||
181 | u_int leds; /* type of leds */ | ||
182 | u_int ledcount; /* used to animate leds */ | ||
183 | u_long ledstate; /* save last state of leds */ | ||
184 | int opticalsupport; /* has the e1 board */ | ||
185 | /* an optical Interface */ | ||
186 | int dslot; /* channel # of d-channel (E1) default 16 */ | ||
187 | |||
188 | u_long wdcount; /* every 500 ms we need to */ | ||
189 | /* send the watchdog a signal */ | ||
190 | u_char wdbyte; /* watchdog toggle byte */ | ||
191 | u_int activity[8]; /* if there is any action on this */ | ||
192 | /* port (will be cleared after */ | ||
193 | /* showing led-states) */ | ||
194 | int e1_state; /* keep track of last state */ | ||
195 | int e1_getclock; /* if sync is retrieved from interface */ | ||
196 | int syncronized; /* keep track of existing sync interface */ | ||
197 | int e1_resync; /* resync jobs */ | ||
198 | |||
199 | spinlock_t lock; /* the lock */ | ||
200 | |||
201 | /* | ||
202 | * the channel index is counted from 0, regardless where the channel | ||
203 | * is located on the hfc-channel. | ||
204 | * the bch->channel is equvalent to the hfc-channel | ||
205 | */ | ||
206 | struct hfc_chan chan[32]; | ||
207 | u_char created[8]; /* what port is created */ | ||
208 | signed char slot_owner[256]; /* owner channel of slot */ | ||
209 | }; | ||
210 | |||
211 | /* PLX GPIOs */ | ||
212 | #define PLX_GPIO4_DIR_BIT 13 | ||
213 | #define PLX_GPIO4_BIT 14 | ||
214 | #define PLX_GPIO5_DIR_BIT 16 | ||
215 | #define PLX_GPIO5_BIT 17 | ||
216 | #define PLX_GPIO6_DIR_BIT 19 | ||
217 | #define PLX_GPIO6_BIT 20 | ||
218 | #define PLX_GPIO7_DIR_BIT 22 | ||
219 | #define PLX_GPIO7_BIT 23 | ||
220 | #define PLX_GPIO8_DIR_BIT 25 | ||
221 | #define PLX_GPIO8_BIT 26 | ||
222 | |||
223 | #define PLX_GPIO4 (1 << PLX_GPIO4_BIT) | ||
224 | #define PLX_GPIO5 (1 << PLX_GPIO5_BIT) | ||
225 | #define PLX_GPIO6 (1 << PLX_GPIO6_BIT) | ||
226 | #define PLX_GPIO7 (1 << PLX_GPIO7_BIT) | ||
227 | #define PLX_GPIO8 (1 << PLX_GPIO8_BIT) | ||
228 | |||
229 | #define PLX_GPIO4_DIR (1 << PLX_GPIO4_DIR_BIT) | ||
230 | #define PLX_GPIO5_DIR (1 << PLX_GPIO5_DIR_BIT) | ||
231 | #define PLX_GPIO6_DIR (1 << PLX_GPIO6_DIR_BIT) | ||
232 | #define PLX_GPIO7_DIR (1 << PLX_GPIO7_DIR_BIT) | ||
233 | #define PLX_GPIO8_DIR (1 << PLX_GPIO8_DIR_BIT) | ||
234 | |||
235 | #define PLX_TERM_ON PLX_GPIO7 | ||
236 | #define PLX_SLAVE_EN_N PLX_GPIO5 | ||
237 | #define PLX_MASTER_EN PLX_GPIO6 | ||
238 | #define PLX_SYNC_O_EN PLX_GPIO4 | ||
239 | #define PLX_DSP_RES_N PLX_GPIO8 | ||
240 | /* GPIO4..8 Enable & Set to OUT, SLAVE_EN_N = 1 */ | ||
241 | #define PLX_GPIOC_INIT (PLX_GPIO4_DIR | PLX_GPIO5_DIR | PLX_GPIO6_DIR \ | ||
242 | | PLX_GPIO7_DIR | PLX_GPIO8_DIR | PLX_SLAVE_EN_N) | ||
243 | |||
244 | /* PLX Interrupt Control/STATUS */ | ||
245 | #define PLX_INTCSR_LINTI1_ENABLE 0x01 | ||
246 | #define PLX_INTCSR_LINTI1_STATUS 0x04 | ||
247 | #define PLX_INTCSR_LINTI2_ENABLE 0x08 | ||
248 | #define PLX_INTCSR_LINTI2_STATUS 0x20 | ||
249 | #define PLX_INTCSR_PCIINT_ENABLE 0x40 | ||
250 | |||
251 | /* PLX Registers */ | ||
252 | #define PLX_INTCSR 0x4c | ||
253 | #define PLX_CNTRL 0x50 | ||
254 | #define PLX_GPIOC 0x54 | ||
255 | |||
256 | |||
257 | /* | ||
258 | * REGISTER SETTING FOR HFC-4S/8S AND HFC-E1 | ||
259 | */ | ||
260 | |||
261 | /* write only registers */ | ||
262 | #define R_CIRM 0x00 | ||
263 | #define R_CTRL 0x01 | ||
264 | #define R_BRG_PCM_CFG 0x02 | ||
265 | #define R_RAM_ADDR0 0x08 | ||
266 | #define R_RAM_ADDR1 0x09 | ||
267 | #define R_RAM_ADDR2 0x0A | ||
268 | #define R_FIRST_FIFO 0x0B | ||
269 | #define R_RAM_SZ 0x0C | ||
270 | #define R_FIFO_MD 0x0D | ||
271 | #define R_INC_RES_FIFO 0x0E | ||
272 | #define R_FSM_IDX 0x0F | ||
273 | #define R_FIFO 0x0F | ||
274 | #define R_SLOT 0x10 | ||
275 | #define R_IRQMSK_MISC 0x11 | ||
276 | #define R_SCI_MSK 0x12 | ||
277 | #define R_IRQ_CTRL 0x13 | ||
278 | #define R_PCM_MD0 0x14 | ||
279 | #define R_PCM_MD1 0x15 | ||
280 | #define R_PCM_MD2 0x15 | ||
281 | #define R_SH0H 0x15 | ||
282 | #define R_SH1H 0x15 | ||
283 | #define R_SH0L 0x15 | ||
284 | #define R_SH1L 0x15 | ||
285 | #define R_SL_SEL0 0x15 | ||
286 | #define R_SL_SEL1 0x15 | ||
287 | #define R_SL_SEL2 0x15 | ||
288 | #define R_SL_SEL3 0x15 | ||
289 | #define R_SL_SEL4 0x15 | ||
290 | #define R_SL_SEL5 0x15 | ||
291 | #define R_SL_SEL6 0x15 | ||
292 | #define R_SL_SEL7 0x15 | ||
293 | #define R_ST_SEL 0x16 | ||
294 | #define R_ST_SYNC 0x17 | ||
295 | #define R_CONF_EN 0x18 | ||
296 | #define R_TI_WD 0x1A | ||
297 | #define R_BERT_WD_MD 0x1B | ||
298 | #define R_DTMF 0x1C | ||
299 | #define R_DTMF_N 0x1D | ||
300 | #define R_E1_WR_STA 0x20 | ||
301 | #define R_E1_RD_STA 0x20 | ||
302 | #define R_LOS0 0x22 | ||
303 | #define R_LOS1 0x23 | ||
304 | #define R_RX0 0x24 | ||
305 | #define R_RX_FR0 0x25 | ||
306 | #define R_RX_FR1 0x26 | ||
307 | #define R_TX0 0x28 | ||
308 | #define R_TX1 0x29 | ||
309 | #define R_TX_FR0 0x2C | ||
310 | |||
311 | #define R_TX_FR1 0x2D | ||
312 | #define R_TX_FR2 0x2E | ||
313 | #define R_JATT_ATT 0x2F /* undocumented */ | ||
314 | #define A_ST_RD_STATE 0x30 | ||
315 | #define A_ST_WR_STATE 0x30 | ||
316 | #define R_RX_OFF 0x30 | ||
317 | #define A_ST_CTRL0 0x31 | ||
318 | #define R_SYNC_OUT 0x31 | ||
319 | #define A_ST_CTRL1 0x32 | ||
320 | #define A_ST_CTRL2 0x33 | ||
321 | #define A_ST_SQ_WR 0x34 | ||
322 | #define R_TX_OFF 0x34 | ||
323 | #define R_SYNC_CTRL 0x35 | ||
324 | #define A_ST_CLK_DLY 0x37 | ||
325 | #define R_PWM0 0x38 | ||
326 | #define R_PWM1 0x39 | ||
327 | #define A_ST_B1_TX 0x3C | ||
328 | #define A_ST_B2_TX 0x3D | ||
329 | #define A_ST_D_TX 0x3E | ||
330 | #define R_GPIO_OUT0 0x40 | ||
331 | #define R_GPIO_OUT1 0x41 | ||
332 | #define R_GPIO_EN0 0x42 | ||
333 | #define R_GPIO_EN1 0x43 | ||
334 | #define R_GPIO_SEL 0x44 | ||
335 | #define R_BRG_CTRL 0x45 | ||
336 | #define R_PWM_MD 0x46 | ||
337 | #define R_BRG_MD 0x47 | ||
338 | #define R_BRG_TIM0 0x48 | ||
339 | #define R_BRG_TIM1 0x49 | ||
340 | #define R_BRG_TIM2 0x4A | ||
341 | #define R_BRG_TIM3 0x4B | ||
342 | #define R_BRG_TIM_SEL01 0x4C | ||
343 | #define R_BRG_TIM_SEL23 0x4D | ||
344 | #define R_BRG_TIM_SEL45 0x4E | ||
345 | #define R_BRG_TIM_SEL67 0x4F | ||
346 | #define A_SL_CFG 0xD0 | ||
347 | #define A_CONF 0xD1 | ||
348 | #define A_CH_MSK 0xF4 | ||
349 | #define A_CON_HDLC 0xFA | ||
350 | #define A_SUBCH_CFG 0xFB | ||
351 | #define A_CHANNEL 0xFC | ||
352 | #define A_FIFO_SEQ 0xFD | ||
353 | #define A_IRQ_MSK 0xFF | ||
354 | |||
355 | /* read only registers */ | ||
356 | #define A_Z12 0x04 | ||
357 | #define A_Z1L 0x04 | ||
358 | #define A_Z1 0x04 | ||
359 | #define A_Z1H 0x05 | ||
360 | #define A_Z2L 0x06 | ||
361 | #define A_Z2 0x06 | ||
362 | #define A_Z2H 0x07 | ||
363 | #define A_F1 0x0C | ||
364 | #define A_F12 0x0C | ||
365 | #define A_F2 0x0D | ||
366 | #define R_IRQ_OVIEW 0x10 | ||
367 | #define R_IRQ_MISC 0x11 | ||
368 | #define R_IRQ_STATECH 0x12 | ||
369 | #define R_CONF_OFLOW 0x14 | ||
370 | #define R_RAM_USE 0x15 | ||
371 | #define R_CHIP_ID 0x16 | ||
372 | #define R_BERT_STA 0x17 | ||
373 | #define R_F0_CNTL 0x18 | ||
374 | #define R_F0_CNTH 0x19 | ||
375 | #define R_BERT_EC 0x1A | ||
376 | #define R_BERT_ECL 0x1A | ||
377 | #define R_BERT_ECH 0x1B | ||
378 | #define R_STATUS 0x1C | ||
379 | #define R_CHIP_RV 0x1F | ||
380 | #define R_STATE 0x20 | ||
381 | #define R_SYNC_STA 0x24 | ||
382 | #define R_RX_SL0_0 0x25 | ||
383 | #define R_RX_SL0_1 0x26 | ||
384 | #define R_RX_SL0_2 0x27 | ||
385 | #define R_JATT_DIR 0x2b /* undocumented */ | ||
386 | #define R_SLIP 0x2c | ||
387 | #define A_ST_RD_STA 0x30 | ||
388 | #define R_FAS_EC 0x30 | ||
389 | #define R_FAS_ECL 0x30 | ||
390 | #define R_FAS_ECH 0x31 | ||
391 | #define R_VIO_EC 0x32 | ||
392 | #define R_VIO_ECL 0x32 | ||
393 | #define R_VIO_ECH 0x33 | ||
394 | #define A_ST_SQ_RD 0x34 | ||
395 | #define R_CRC_EC 0x34 | ||
396 | #define R_CRC_ECL 0x34 | ||
397 | #define R_CRC_ECH 0x35 | ||
398 | #define R_E_EC 0x36 | ||
399 | #define R_E_ECL 0x36 | ||
400 | #define R_E_ECH 0x37 | ||
401 | #define R_SA6_SA13_EC 0x38 | ||
402 | #define R_SA6_SA13_ECL 0x38 | ||
403 | #define R_SA6_SA13_ECH 0x39 | ||
404 | #define R_SA6_SA23_EC 0x3A | ||
405 | #define R_SA6_SA23_ECL 0x3A | ||
406 | #define R_SA6_SA23_ECH 0x3B | ||
407 | #define A_ST_B1_RX 0x3C | ||
408 | #define A_ST_B2_RX 0x3D | ||
409 | #define A_ST_D_RX 0x3E | ||
410 | #define A_ST_E_RX 0x3F | ||
411 | #define R_GPIO_IN0 0x40 | ||
412 | #define R_GPIO_IN1 0x41 | ||
413 | #define R_GPI_IN0 0x44 | ||
414 | #define R_GPI_IN1 0x45 | ||
415 | #define R_GPI_IN2 0x46 | ||
416 | #define R_GPI_IN3 0x47 | ||
417 | #define R_INT_DATA 0x88 | ||
418 | #define R_IRQ_FIFO_BL0 0xC8 | ||
419 | #define R_IRQ_FIFO_BL1 0xC9 | ||
420 | #define R_IRQ_FIFO_BL2 0xCA | ||
421 | #define R_IRQ_FIFO_BL3 0xCB | ||
422 | #define R_IRQ_FIFO_BL4 0xCC | ||
423 | #define R_IRQ_FIFO_BL5 0xCD | ||
424 | #define R_IRQ_FIFO_BL6 0xCE | ||
425 | #define R_IRQ_FIFO_BL7 0xCF | ||
426 | |||
427 | /* read and write registers */ | ||
428 | #define A_FIFO_DATA0 0x80 | ||
429 | #define A_FIFO_DATA1 0x80 | ||
430 | #define A_FIFO_DATA2 0x80 | ||
431 | #define A_FIFO_DATA0_NOINC 0x84 | ||
432 | #define A_FIFO_DATA1_NOINC 0x84 | ||
433 | #define A_FIFO_DATA2_NOINC 0x84 | ||
434 | #define R_RAM_DATA 0xC0 | ||
435 | |||
436 | |||
437 | /* | ||
438 | * BIT SETTING FOR HFC-4S/8S AND HFC-E1 | ||
439 | */ | ||
440 | |||
441 | /* chapter 2: universal bus interface */ | ||
442 | /* R_CIRM */ | ||
443 | #define V_IRQ_SEL 0x01 | ||
444 | #define V_SRES 0x08 | ||
445 | #define V_HFCRES 0x10 | ||
446 | #define V_PCMRES 0x20 | ||
447 | #define V_STRES 0x40 | ||
448 | #define V_ETRES 0x40 | ||
449 | #define V_RLD_EPR 0x80 | ||
450 | /* R_CTRL */ | ||
451 | #define V_FIFO_LPRIO 0x02 | ||
452 | #define V_SLOW_RD 0x04 | ||
453 | #define V_EXT_RAM 0x08 | ||
454 | #define V_CLK_OFF 0x20 | ||
455 | #define V_ST_CLK 0x40 | ||
456 | /* R_RAM_ADDR0 */ | ||
457 | #define V_RAM_ADDR2 0x01 | ||
458 | #define V_ADDR_RES 0x40 | ||
459 | #define V_ADDR_INC 0x80 | ||
460 | /* R_RAM_SZ */ | ||
461 | #define V_RAM_SZ 0x01 | ||
462 | #define V_PWM0_16KHZ 0x10 | ||
463 | #define V_PWM1_16KHZ 0x20 | ||
464 | #define V_FZ_MD 0x80 | ||
465 | /* R_CHIP_ID */ | ||
466 | #define V_PNP_IRQ 0x01 | ||
467 | #define V_CHIP_ID 0x10 | ||
468 | |||
469 | /* chapter 3: data flow */ | ||
470 | /* R_FIRST_FIFO */ | ||
471 | #define V_FIRST_FIRO_DIR 0x01 | ||
472 | #define V_FIRST_FIFO_NUM 0x02 | ||
473 | /* R_FIFO_MD */ | ||
474 | #define V_FIFO_MD 0x01 | ||
475 | #define V_CSM_MD 0x04 | ||
476 | #define V_FSM_MD 0x08 | ||
477 | #define V_FIFO_SZ 0x10 | ||
478 | /* R_FIFO */ | ||
479 | #define V_FIFO_DIR 0x01 | ||
480 | #define V_FIFO_NUM 0x02 | ||
481 | #define V_REV 0x80 | ||
482 | /* R_SLOT */ | ||
483 | #define V_SL_DIR 0x01 | ||
484 | #define V_SL_NUM 0x02 | ||
485 | /* A_SL_CFG */ | ||
486 | #define V_CH_DIR 0x01 | ||
487 | #define V_CH_SEL 0x02 | ||
488 | #define V_ROUTING 0x40 | ||
489 | /* A_CON_HDLC */ | ||
490 | #define V_IFF 0x01 | ||
491 | #define V_HDLC_TRP 0x02 | ||
492 | #define V_TRP_IRQ 0x04 | ||
493 | #define V_DATA_FLOW 0x20 | ||
494 | /* A_SUBCH_CFG */ | ||
495 | #define V_BIT_CNT 0x01 | ||
496 | #define V_START_BIT 0x08 | ||
497 | #define V_LOOP_FIFO 0x40 | ||
498 | #define V_INV_DATA 0x80 | ||
499 | /* A_CHANNEL */ | ||
500 | #define V_CH_DIR0 0x01 | ||
501 | #define V_CH_NUM0 0x02 | ||
502 | /* A_FIFO_SEQ */ | ||
503 | #define V_NEXT_FIFO_DIR 0x01 | ||
504 | #define V_NEXT_FIFO_NUM 0x02 | ||
505 | #define V_SEQ_END 0x40 | ||
506 | |||
507 | /* chapter 4: FIFO handling and HDLC controller */ | ||
508 | /* R_INC_RES_FIFO */ | ||
509 | #define V_INC_F 0x01 | ||
510 | #define V_RES_F 0x02 | ||
511 | #define V_RES_LOST 0x04 | ||
512 | |||
513 | /* chapter 5: S/T interface */ | ||
514 | /* R_SCI_MSK */ | ||
515 | #define V_SCI_MSK_ST0 0x01 | ||
516 | #define V_SCI_MSK_ST1 0x02 | ||
517 | #define V_SCI_MSK_ST2 0x04 | ||
518 | #define V_SCI_MSK_ST3 0x08 | ||
519 | #define V_SCI_MSK_ST4 0x10 | ||
520 | #define V_SCI_MSK_ST5 0x20 | ||
521 | #define V_SCI_MSK_ST6 0x40 | ||
522 | #define V_SCI_MSK_ST7 0x80 | ||
523 | /* R_ST_SEL */ | ||
524 | #define V_ST_SEL 0x01 | ||
525 | #define V_MULT_ST 0x08 | ||
526 | /* R_ST_SYNC */ | ||
527 | #define V_SYNC_SEL 0x01 | ||
528 | #define V_AUTO_SYNC 0x08 | ||
529 | /* A_ST_WR_STA */ | ||
530 | #define V_ST_SET_STA 0x01 | ||
531 | #define V_ST_LD_STA 0x10 | ||
532 | #define V_ST_ACT 0x20 | ||
533 | #define V_SET_G2_G3 0x80 | ||
534 | /* A_ST_CTRL0 */ | ||
535 | #define V_B1_EN 0x01 | ||
536 | #define V_B2_EN 0x02 | ||
537 | #define V_ST_MD 0x04 | ||
538 | #define V_D_PRIO 0x08 | ||
539 | #define V_SQ_EN 0x10 | ||
540 | #define V_96KHZ 0x20 | ||
541 | #define V_TX_LI 0x40 | ||
542 | #define V_ST_STOP 0x80 | ||
543 | /* A_ST_CTRL1 */ | ||
544 | #define V_G2_G3_EN 0x01 | ||
545 | #define V_D_HI 0x04 | ||
546 | #define V_E_IGNO 0x08 | ||
547 | #define V_E_LO 0x10 | ||
548 | #define V_B12_SWAP 0x80 | ||
549 | /* A_ST_CTRL2 */ | ||
550 | #define V_B1_RX_EN 0x01 | ||
551 | #define V_B2_RX_EN 0x02 | ||
552 | #define V_ST_TRIS 0x40 | ||
553 | /* A_ST_CLK_DLY */ | ||
554 | #define V_ST_CK_DLY 0x01 | ||
555 | #define V_ST_SMPL 0x10 | ||
556 | /* A_ST_D_TX */ | ||
557 | #define V_ST_D_TX 0x40 | ||
558 | /* R_IRQ_STATECH */ | ||
559 | #define V_SCI_ST0 0x01 | ||
560 | #define V_SCI_ST1 0x02 | ||
561 | #define V_SCI_ST2 0x04 | ||
562 | #define V_SCI_ST3 0x08 | ||
563 | #define V_SCI_ST4 0x10 | ||
564 | #define V_SCI_ST5 0x20 | ||
565 | #define V_SCI_ST6 0x40 | ||
566 | #define V_SCI_ST7 0x80 | ||
567 | /* A_ST_RD_STA */ | ||
568 | #define V_ST_STA 0x01 | ||
569 | #define V_FR_SYNC_ST 0x10 | ||
570 | #define V_TI2_EXP 0x20 | ||
571 | #define V_INFO0 0x40 | ||
572 | #define V_G2_G3 0x80 | ||
573 | /* A_ST_SQ_RD */ | ||
574 | #define V_ST_SQ 0x01 | ||
575 | #define V_MF_RX_RDY 0x10 | ||
576 | #define V_MF_TX_RDY 0x80 | ||
577 | /* A_ST_D_RX */ | ||
578 | #define V_ST_D_RX 0x40 | ||
579 | /* A_ST_E_RX */ | ||
580 | #define V_ST_E_RX 0x40 | ||
581 | |||
582 | /* chapter 5: E1 interface */ | ||
583 | /* R_E1_WR_STA */ | ||
584 | /* R_E1_RD_STA */ | ||
585 | #define V_E1_SET_STA 0x01 | ||
586 | #define V_E1_LD_STA 0x10 | ||
587 | /* R_RX0 */ | ||
588 | #define V_RX_CODE 0x01 | ||
589 | #define V_RX_FBAUD 0x04 | ||
590 | #define V_RX_CMI 0x08 | ||
591 | #define V_RX_INV_CMI 0x10 | ||
592 | #define V_RX_INV_CLK 0x20 | ||
593 | #define V_RX_INV_DATA 0x40 | ||
594 | #define V_AIS_ITU 0x80 | ||
595 | /* R_RX_FR0 */ | ||
596 | #define V_NO_INSYNC 0x01 | ||
597 | #define V_AUTO_RESYNC 0x02 | ||
598 | #define V_AUTO_RECO 0x04 | ||
599 | #define V_SWORD_COND 0x08 | ||
600 | #define V_SYNC_LOSS 0x10 | ||
601 | #define V_XCRC_SYNC 0x20 | ||
602 | #define V_MF_RESYNC 0x40 | ||
603 | #define V_RESYNC 0x80 | ||
604 | /* R_RX_FR1 */ | ||
605 | #define V_RX_MF 0x01 | ||
606 | #define V_RX_MF_SYNC 0x02 | ||
607 | #define V_RX_SL0_RAM 0x04 | ||
608 | #define V_ERR_SIM 0x20 | ||
609 | #define V_RES_NMF 0x40 | ||
610 | /* R_TX0 */ | ||
611 | #define V_TX_CODE 0x01 | ||
612 | #define V_TX_FBAUD 0x04 | ||
613 | #define V_TX_CMI_CODE 0x08 | ||
614 | #define V_TX_INV_CMI_CODE 0x10 | ||
615 | #define V_TX_INV_CLK 0x20 | ||
616 | #define V_TX_INV_DATA 0x40 | ||
617 | #define V_OUT_EN 0x80 | ||
618 | /* R_TX1 */ | ||
619 | #define V_INV_CLK 0x01 | ||
620 | #define V_EXCHG_DATA_LI 0x02 | ||
621 | #define V_AIS_OUT 0x04 | ||
622 | #define V_ATX 0x20 | ||
623 | #define V_NTRI 0x40 | ||
624 | #define V_AUTO_ERR_RES 0x80 | ||
625 | /* R_TX_FR0 */ | ||
626 | #define V_TRP_FAS 0x01 | ||
627 | #define V_TRP_NFAS 0x02 | ||
628 | #define V_TRP_RAL 0x04 | ||
629 | #define V_TRP_SA 0x08 | ||
630 | /* R_TX_FR1 */ | ||
631 | #define V_TX_FAS 0x01 | ||
632 | #define V_TX_NFAS 0x02 | ||
633 | #define V_TX_RAL 0x04 | ||
634 | #define V_TX_SA 0x08 | ||
635 | /* R_TX_FR2 */ | ||
636 | #define V_TX_MF 0x01 | ||
637 | #define V_TRP_SL0 0x02 | ||
638 | #define V_TX_SL0_RAM 0x04 | ||
639 | #define V_TX_E 0x10 | ||
640 | #define V_NEG_E 0x20 | ||
641 | #define V_XS12_ON 0x40 | ||
642 | #define V_XS15_ON 0x80 | ||
643 | /* R_RX_OFF */ | ||
644 | #define V_RX_SZ 0x01 | ||
645 | #define V_RX_INIT 0x04 | ||
646 | /* R_SYNC_OUT */ | ||
647 | #define V_SYNC_E1_RX 0x01 | ||
648 | #define V_IPATS0 0x20 | ||
649 | #define V_IPATS1 0x40 | ||
650 | #define V_IPATS2 0x80 | ||
651 | /* R_TX_OFF */ | ||
652 | #define V_TX_SZ 0x01 | ||
653 | #define V_TX_INIT 0x04 | ||
654 | /* R_SYNC_CTRL */ | ||
655 | #define V_EXT_CLK_SYNC 0x01 | ||
656 | #define V_SYNC_OFFS 0x02 | ||
657 | #define V_PCM_SYNC 0x04 | ||
658 | #define V_NEG_CLK 0x08 | ||
659 | #define V_HCLK 0x10 | ||
660 | /* | ||
661 | #define V_JATT_AUTO_DEL 0x20 | ||
662 | #define V_JATT_AUTO 0x40 | ||
663 | */ | ||
664 | #define V_JATT_OFF 0x80 | ||
665 | /* R_STATE */ | ||
666 | #define V_E1_STA 0x01 | ||
667 | #define V_ALT_FR_RX 0x40 | ||
668 | #define V_ALT_FR_TX 0x80 | ||
669 | /* R_SYNC_STA */ | ||
670 | #define V_RX_STA 0x01 | ||
671 | #define V_FR_SYNC_E1 0x04 | ||
672 | #define V_SIG_LOS 0x08 | ||
673 | #define V_MFA_STA 0x10 | ||
674 | #define V_AIS 0x40 | ||
675 | #define V_NO_MF_SYNC 0x80 | ||
676 | /* R_RX_SL0_0 */ | ||
677 | #define V_SI_FAS 0x01 | ||
678 | #define V_SI_NFAS 0x02 | ||
679 | #define V_A 0x04 | ||
680 | #define V_CRC_OK 0x08 | ||
681 | #define V_TX_E1 0x10 | ||
682 | #define V_TX_E2 0x20 | ||
683 | #define V_RX_E1 0x40 | ||
684 | #define V_RX_E2 0x80 | ||
685 | /* R_SLIP */ | ||
686 | #define V_SLIP_RX 0x01 | ||
687 | #define V_FOSLIP_RX 0x08 | ||
688 | #define V_SLIP_TX 0x10 | ||
689 | #define V_FOSLIP_TX 0x80 | ||
690 | |||
691 | /* chapter 6: PCM interface */ | ||
692 | /* R_PCM_MD0 */ | ||
693 | #define V_PCM_MD 0x01 | ||
694 | #define V_C4_POL 0x02 | ||
695 | #define V_F0_NEG 0x04 | ||
696 | #define V_F0_LEN 0x08 | ||
697 | #define V_PCM_ADDR 0x10 | ||
698 | /* R_SL_SEL0 */ | ||
699 | #define V_SL_SEL0 0x01 | ||
700 | #define V_SH_SEL0 0x80 | ||
701 | /* R_SL_SEL1 */ | ||
702 | #define V_SL_SEL1 0x01 | ||
703 | #define V_SH_SEL1 0x80 | ||
704 | /* R_SL_SEL2 */ | ||
705 | #define V_SL_SEL2 0x01 | ||
706 | #define V_SH_SEL2 0x80 | ||
707 | /* R_SL_SEL3 */ | ||
708 | #define V_SL_SEL3 0x01 | ||
709 | #define V_SH_SEL3 0x80 | ||
710 | /* R_SL_SEL4 */ | ||
711 | #define V_SL_SEL4 0x01 | ||
712 | #define V_SH_SEL4 0x80 | ||
713 | /* R_SL_SEL5 */ | ||
714 | #define V_SL_SEL5 0x01 | ||
715 | #define V_SH_SEL5 0x80 | ||
716 | /* R_SL_SEL6 */ | ||
717 | #define V_SL_SEL6 0x01 | ||
718 | #define V_SH_SEL6 0x80 | ||
719 | /* R_SL_SEL7 */ | ||
720 | #define V_SL_SEL7 0x01 | ||
721 | #define V_SH_SEL7 0x80 | ||
722 | /* R_PCM_MD1 */ | ||
723 | #define V_ODEC_CON 0x01 | ||
724 | #define V_PLL_ADJ 0x04 | ||
725 | #define V_PCM_DR 0x10 | ||
726 | #define V_PCM_LOOP 0x40 | ||
727 | /* R_PCM_MD2 */ | ||
728 | #define V_SYNC_PLL 0x02 | ||
729 | #define V_SYNC_SRC 0x04 | ||
730 | #define V_SYNC_OUT 0x08 | ||
731 | #define V_ICR_FR_TIME 0x40 | ||
732 | #define V_EN_PLL 0x80 | ||
733 | |||
734 | /* chapter 7: pulse width modulation */ | ||
735 | /* R_PWM_MD */ | ||
736 | #define V_EXT_IRQ_EN 0x08 | ||
737 | #define V_PWM0_MD 0x10 | ||
738 | #define V_PWM1_MD 0x40 | ||
739 | |||
740 | /* chapter 8: multiparty audio conferences */ | ||
741 | /* R_CONF_EN */ | ||
742 | #define V_CONF_EN 0x01 | ||
743 | #define V_ULAW 0x80 | ||
744 | /* A_CONF */ | ||
745 | #define V_CONF_NUM 0x01 | ||
746 | #define V_NOISE_SUPPR 0x08 | ||
747 | #define V_ATT_LEV 0x20 | ||
748 | #define V_CONF_SL 0x80 | ||
749 | /* R_CONF_OFLOW */ | ||
750 | #define V_CONF_OFLOW0 0x01 | ||
751 | #define V_CONF_OFLOW1 0x02 | ||
752 | #define V_CONF_OFLOW2 0x04 | ||
753 | #define V_CONF_OFLOW3 0x08 | ||
754 | #define V_CONF_OFLOW4 0x10 | ||
755 | #define V_CONF_OFLOW5 0x20 | ||
756 | #define V_CONF_OFLOW6 0x40 | ||
757 | #define V_CONF_OFLOW7 0x80 | ||
758 | |||
759 | /* chapter 9: DTMF contoller */ | ||
760 | /* R_DTMF0 */ | ||
761 | #define V_DTMF_EN 0x01 | ||
762 | #define V_HARM_SEL 0x02 | ||
763 | #define V_DTMF_RX_CH 0x04 | ||
764 | #define V_DTMF_STOP 0x08 | ||
765 | #define V_CHBL_SEL 0x10 | ||
766 | #define V_RST_DTMF 0x40 | ||
767 | #define V_ULAW_SEL 0x80 | ||
768 | |||
769 | /* chapter 10: BERT */ | ||
770 | /* R_BERT_WD_MD */ | ||
771 | #define V_PAT_SEQ 0x01 | ||
772 | #define V_BERT_ERR 0x08 | ||
773 | #define V_AUTO_WD_RES 0x20 | ||
774 | #define V_WD_RES 0x80 | ||
775 | /* R_BERT_STA */ | ||
776 | #define V_BERT_SYNC_SRC 0x01 | ||
777 | #define V_BERT_SYNC 0x10 | ||
778 | #define V_BERT_INV_DATA 0x20 | ||
779 | |||
780 | /* chapter 11: auxiliary interface */ | ||
781 | /* R_BRG_PCM_CFG */ | ||
782 | #define V_BRG_EN 0x01 | ||
783 | #define V_BRG_MD 0x02 | ||
784 | #define V_PCM_CLK 0x20 | ||
785 | #define V_ADDR_WRDLY 0x40 | ||
786 | /* R_BRG_CTRL */ | ||
787 | #define V_BRG_CS 0x01 | ||
788 | #define V_BRG_ADDR 0x08 | ||
789 | #define V_BRG_CS_SRC 0x80 | ||
790 | /* R_BRG_MD */ | ||
791 | #define V_BRG_MD0 0x01 | ||
792 | #define V_BRG_MD1 0x02 | ||
793 | #define V_BRG_MD2 0x04 | ||
794 | #define V_BRG_MD3 0x08 | ||
795 | #define V_BRG_MD4 0x10 | ||
796 | #define V_BRG_MD5 0x20 | ||
797 | #define V_BRG_MD6 0x40 | ||
798 | #define V_BRG_MD7 0x80 | ||
799 | /* R_BRG_TIM0 */ | ||
800 | #define V_BRG_TIM0_IDLE 0x01 | ||
801 | #define V_BRG_TIM0_CLK 0x10 | ||
802 | /* R_BRG_TIM1 */ | ||
803 | #define V_BRG_TIM1_IDLE 0x01 | ||
804 | #define V_BRG_TIM1_CLK 0x10 | ||
805 | /* R_BRG_TIM2 */ | ||
806 | #define V_BRG_TIM2_IDLE 0x01 | ||
807 | #define V_BRG_TIM2_CLK 0x10 | ||
808 | /* R_BRG_TIM3 */ | ||
809 | #define V_BRG_TIM3_IDLE 0x01 | ||
810 | #define V_BRG_TIM3_CLK 0x10 | ||
811 | /* R_BRG_TIM_SEL01 */ | ||
812 | #define V_BRG_WR_SEL0 0x01 | ||
813 | #define V_BRG_RD_SEL0 0x04 | ||
814 | #define V_BRG_WR_SEL1 0x10 | ||
815 | #define V_BRG_RD_SEL1 0x40 | ||
816 | /* R_BRG_TIM_SEL23 */ | ||
817 | #define V_BRG_WR_SEL2 0x01 | ||
818 | #define V_BRG_RD_SEL2 0x04 | ||
819 | #define V_BRG_WR_SEL3 0x10 | ||
820 | #define V_BRG_RD_SEL3 0x40 | ||
821 | /* R_BRG_TIM_SEL45 */ | ||
822 | #define V_BRG_WR_SEL4 0x01 | ||
823 | #define V_BRG_RD_SEL4 0x04 | ||
824 | #define V_BRG_WR_SEL5 0x10 | ||
825 | #define V_BRG_RD_SEL5 0x40 | ||
826 | /* R_BRG_TIM_SEL67 */ | ||
827 | #define V_BRG_WR_SEL6 0x01 | ||
828 | #define V_BRG_RD_SEL6 0x04 | ||
829 | #define V_BRG_WR_SEL7 0x10 | ||
830 | #define V_BRG_RD_SEL7 0x40 | ||
831 | |||
832 | /* chapter 12: clock, reset, interrupt, timer and watchdog */ | ||
833 | /* R_IRQMSK_MISC */ | ||
834 | #define V_STA_IRQMSK 0x01 | ||
835 | #define V_TI_IRQMSK 0x02 | ||
836 | #define V_PROC_IRQMSK 0x04 | ||
837 | #define V_DTMF_IRQMSK 0x08 | ||
838 | #define V_IRQ1S_MSK 0x10 | ||
839 | #define V_SA6_IRQMSK 0x20 | ||
840 | #define V_RX_EOMF_MSK 0x40 | ||
841 | #define V_TX_EOMF_MSK 0x80 | ||
842 | /* R_IRQ_CTRL */ | ||
843 | #define V_FIFO_IRQ 0x01 | ||
844 | #define V_GLOB_IRQ_EN 0x08 | ||
845 | #define V_IRQ_POL 0x10 | ||
846 | /* R_TI_WD */ | ||
847 | #define V_EV_TS 0x01 | ||
848 | #define V_WD_TS 0x10 | ||
849 | /* A_IRQ_MSK */ | ||
850 | #define V_IRQ 0x01 | ||
851 | #define V_BERT_EN 0x02 | ||
852 | #define V_MIX_IRQ 0x04 | ||
853 | /* R_IRQ_OVIEW */ | ||
854 | #define V_IRQ_FIFO_BL0 0x01 | ||
855 | #define V_IRQ_FIFO_BL1 0x02 | ||
856 | #define V_IRQ_FIFO_BL2 0x04 | ||
857 | #define V_IRQ_FIFO_BL3 0x08 | ||
858 | #define V_IRQ_FIFO_BL4 0x10 | ||
859 | #define V_IRQ_FIFO_BL5 0x20 | ||
860 | #define V_IRQ_FIFO_BL6 0x40 | ||
861 | #define V_IRQ_FIFO_BL7 0x80 | ||
862 | /* R_IRQ_MISC */ | ||
863 | #define V_STA_IRQ 0x01 | ||
864 | #define V_TI_IRQ 0x02 | ||
865 | #define V_IRQ_PROC 0x04 | ||
866 | #define V_DTMF_IRQ 0x08 | ||
867 | #define V_IRQ1S 0x10 | ||
868 | #define V_SA6_IRQ 0x20 | ||
869 | #define V_RX_EOMF 0x40 | ||
870 | #define V_TX_EOMF 0x80 | ||
871 | /* R_STATUS */ | ||
872 | #define V_BUSY 0x01 | ||
873 | #define V_PROC 0x02 | ||
874 | #define V_DTMF_STA 0x04 | ||
875 | #define V_LOST_STA 0x08 | ||
876 | #define V_SYNC_IN 0x10 | ||
877 | #define V_EXT_IRQSTA 0x20 | ||
878 | #define V_MISC_IRQSTA 0x40 | ||
879 | #define V_FR_IRQSTA 0x80 | ||
880 | /* R_IRQ_FIFO_BL0 */ | ||
881 | #define V_IRQ_FIFO0_TX 0x01 | ||
882 | #define V_IRQ_FIFO0_RX 0x02 | ||
883 | #define V_IRQ_FIFO1_TX 0x04 | ||
884 | #define V_IRQ_FIFO1_RX 0x08 | ||
885 | #define V_IRQ_FIFO2_TX 0x10 | ||
886 | #define V_IRQ_FIFO2_RX 0x20 | ||
887 | #define V_IRQ_FIFO3_TX 0x40 | ||
888 | #define V_IRQ_FIFO3_RX 0x80 | ||
889 | /* R_IRQ_FIFO_BL1 */ | ||
890 | #define V_IRQ_FIFO4_TX 0x01 | ||
891 | #define V_IRQ_FIFO4_RX 0x02 | ||
892 | #define V_IRQ_FIFO5_TX 0x04 | ||
893 | #define V_IRQ_FIFO5_RX 0x08 | ||
894 | #define V_IRQ_FIFO6_TX 0x10 | ||
895 | #define V_IRQ_FIFO6_RX 0x20 | ||
896 | #define V_IRQ_FIFO7_TX 0x40 | ||
897 | #define V_IRQ_FIFO7_RX 0x80 | ||
898 | /* R_IRQ_FIFO_BL2 */ | ||
899 | #define V_IRQ_FIFO8_TX 0x01 | ||
900 | #define V_IRQ_FIFO8_RX 0x02 | ||
901 | #define V_IRQ_FIFO9_TX 0x04 | ||
902 | #define V_IRQ_FIFO9_RX 0x08 | ||
903 | #define V_IRQ_FIFO10_TX 0x10 | ||
904 | #define V_IRQ_FIFO10_RX 0x20 | ||
905 | #define V_IRQ_FIFO11_TX 0x40 | ||
906 | #define V_IRQ_FIFO11_RX 0x80 | ||
907 | /* R_IRQ_FIFO_BL3 */ | ||
908 | #define V_IRQ_FIFO12_TX 0x01 | ||
909 | #define V_IRQ_FIFO12_RX 0x02 | ||
910 | #define V_IRQ_FIFO13_TX 0x04 | ||
911 | #define V_IRQ_FIFO13_RX 0x08 | ||
912 | #define V_IRQ_FIFO14_TX 0x10 | ||
913 | #define V_IRQ_FIFO14_RX 0x20 | ||
914 | #define V_IRQ_FIFO15_TX 0x40 | ||
915 | #define V_IRQ_FIFO15_RX 0x80 | ||
916 | /* R_IRQ_FIFO_BL4 */ | ||
917 | #define V_IRQ_FIFO16_TX 0x01 | ||
918 | #define V_IRQ_FIFO16_RX 0x02 | ||
919 | #define V_IRQ_FIFO17_TX 0x04 | ||
920 | #define V_IRQ_FIFO17_RX 0x08 | ||
921 | #define V_IRQ_FIFO18_TX 0x10 | ||
922 | #define V_IRQ_FIFO18_RX 0x20 | ||
923 | #define V_IRQ_FIFO19_TX 0x40 | ||
924 | #define V_IRQ_FIFO19_RX 0x80 | ||
925 | /* R_IRQ_FIFO_BL5 */ | ||
926 | #define V_IRQ_FIFO20_TX 0x01 | ||
927 | #define V_IRQ_FIFO20_RX 0x02 | ||
928 | #define V_IRQ_FIFO21_TX 0x04 | ||
929 | #define V_IRQ_FIFO21_RX 0x08 | ||
930 | #define V_IRQ_FIFO22_TX 0x10 | ||
931 | #define V_IRQ_FIFO22_RX 0x20 | ||
932 | #define V_IRQ_FIFO23_TX 0x40 | ||
933 | #define V_IRQ_FIFO23_RX 0x80 | ||
934 | /* R_IRQ_FIFO_BL6 */ | ||
935 | #define V_IRQ_FIFO24_TX 0x01 | ||
936 | #define V_IRQ_FIFO24_RX 0x02 | ||
937 | #define V_IRQ_FIFO25_TX 0x04 | ||
938 | #define V_IRQ_FIFO25_RX 0x08 | ||
939 | #define V_IRQ_FIFO26_TX 0x10 | ||
940 | #define V_IRQ_FIFO26_RX 0x20 | ||
941 | #define V_IRQ_FIFO27_TX 0x40 | ||
942 | #define V_IRQ_FIFO27_RX 0x80 | ||
943 | /* R_IRQ_FIFO_BL7 */ | ||
944 | #define V_IRQ_FIFO28_TX 0x01 | ||
945 | #define V_IRQ_FIFO28_RX 0x02 | ||
946 | #define V_IRQ_FIFO29_TX 0x04 | ||
947 | #define V_IRQ_FIFO29_RX 0x08 | ||
948 | #define V_IRQ_FIFO30_TX 0x10 | ||
949 | #define V_IRQ_FIFO30_RX 0x20 | ||
950 | #define V_IRQ_FIFO31_TX 0x40 | ||
951 | #define V_IRQ_FIFO31_RX 0x80 | ||
952 | |||
953 | /* chapter 13: general purpose I/O pins (GPIO) and input pins (GPI) */ | ||
954 | /* R_GPIO_OUT0 */ | ||
955 | #define V_GPIO_OUT0 0x01 | ||
956 | #define V_GPIO_OUT1 0x02 | ||
957 | #define V_GPIO_OUT2 0x04 | ||
958 | #define V_GPIO_OUT3 0x08 | ||
959 | #define V_GPIO_OUT4 0x10 | ||
960 | #define V_GPIO_OUT5 0x20 | ||
961 | #define V_GPIO_OUT6 0x40 | ||
962 | #define V_GPIO_OUT7 0x80 | ||
963 | /* R_GPIO_OUT1 */ | ||
964 | #define V_GPIO_OUT8 0x01 | ||
965 | #define V_GPIO_OUT9 0x02 | ||
966 | #define V_GPIO_OUT10 0x04 | ||
967 | #define V_GPIO_OUT11 0x08 | ||
968 | #define V_GPIO_OUT12 0x10 | ||
969 | #define V_GPIO_OUT13 0x20 | ||
970 | #define V_GPIO_OUT14 0x40 | ||
971 | #define V_GPIO_OUT15 0x80 | ||
972 | /* R_GPIO_EN0 */ | ||
973 | #define V_GPIO_EN0 0x01 | ||
974 | #define V_GPIO_EN1 0x02 | ||
975 | #define V_GPIO_EN2 0x04 | ||
976 | #define V_GPIO_EN3 0x08 | ||
977 | #define V_GPIO_EN4 0x10 | ||
978 | #define V_GPIO_EN5 0x20 | ||
979 | #define V_GPIO_EN6 0x40 | ||
980 | #define V_GPIO_EN7 0x80 | ||
981 | /* R_GPIO_EN1 */ | ||
982 | #define V_GPIO_EN8 0x01 | ||
983 | #define V_GPIO_EN9 0x02 | ||
984 | #define V_GPIO_EN10 0x04 | ||
985 | #define V_GPIO_EN11 0x08 | ||
986 | #define V_GPIO_EN12 0x10 | ||
987 | #define V_GPIO_EN13 0x20 | ||
988 | #define V_GPIO_EN14 0x40 | ||
989 | #define V_GPIO_EN15 0x80 | ||
990 | /* R_GPIO_SEL */ | ||
991 | #define V_GPIO_SEL0 0x01 | ||
992 | #define V_GPIO_SEL1 0x02 | ||
993 | #define V_GPIO_SEL2 0x04 | ||
994 | #define V_GPIO_SEL3 0x08 | ||
995 | #define V_GPIO_SEL4 0x10 | ||
996 | #define V_GPIO_SEL5 0x20 | ||
997 | #define V_GPIO_SEL6 0x40 | ||
998 | #define V_GPIO_SEL7 0x80 | ||
999 | /* R_GPIO_IN0 */ | ||
1000 | #define V_GPIO_IN0 0x01 | ||
1001 | #define V_GPIO_IN1 0x02 | ||
1002 | #define V_GPIO_IN2 0x04 | ||
1003 | #define V_GPIO_IN3 0x08 | ||
1004 | #define V_GPIO_IN4 0x10 | ||
1005 | #define V_GPIO_IN5 0x20 | ||
1006 | #define V_GPIO_IN6 0x40 | ||
1007 | #define V_GPIO_IN7 0x80 | ||
1008 | /* R_GPIO_IN1 */ | ||
1009 | #define V_GPIO_IN8 0x01 | ||
1010 | #define V_GPIO_IN9 0x02 | ||
1011 | #define V_GPIO_IN10 0x04 | ||
1012 | #define V_GPIO_IN11 0x08 | ||
1013 | #define V_GPIO_IN12 0x10 | ||
1014 | #define V_GPIO_IN13 0x20 | ||
1015 | #define V_GPIO_IN14 0x40 | ||
1016 | #define V_GPIO_IN15 0x80 | ||
1017 | /* R_GPI_IN0 */ | ||
1018 | #define V_GPI_IN0 0x01 | ||
1019 | #define V_GPI_IN1 0x02 | ||
1020 | #define V_GPI_IN2 0x04 | ||
1021 | #define V_GPI_IN3 0x08 | ||
1022 | #define V_GPI_IN4 0x10 | ||
1023 | #define V_GPI_IN5 0x20 | ||
1024 | #define V_GPI_IN6 0x40 | ||
1025 | #define V_GPI_IN7 0x80 | ||
1026 | /* R_GPI_IN1 */ | ||
1027 | #define V_GPI_IN8 0x01 | ||
1028 | #define V_GPI_IN9 0x02 | ||
1029 | #define V_GPI_IN10 0x04 | ||
1030 | #define V_GPI_IN11 0x08 | ||
1031 | #define V_GPI_IN12 0x10 | ||
1032 | #define V_GPI_IN13 0x20 | ||
1033 | #define V_GPI_IN14 0x40 | ||
1034 | #define V_GPI_IN15 0x80 | ||
1035 | /* R_GPI_IN2 */ | ||
1036 | #define V_GPI_IN16 0x01 | ||
1037 | #define V_GPI_IN17 0x02 | ||
1038 | #define V_GPI_IN18 0x04 | ||
1039 | #define V_GPI_IN19 0x08 | ||
1040 | #define V_GPI_IN20 0x10 | ||
1041 | #define V_GPI_IN21 0x20 | ||
1042 | #define V_GPI_IN22 0x40 | ||
1043 | #define V_GPI_IN23 0x80 | ||
1044 | /* R_GPI_IN3 */ | ||
1045 | #define V_GPI_IN24 0x01 | ||
1046 | #define V_GPI_IN25 0x02 | ||
1047 | #define V_GPI_IN26 0x04 | ||
1048 | #define V_GPI_IN27 0x08 | ||
1049 | #define V_GPI_IN28 0x10 | ||
1050 | #define V_GPI_IN29 0x20 | ||
1051 | #define V_GPI_IN30 0x40 | ||
1052 | #define V_GPI_IN31 0x80 | ||
1053 | |||
1054 | /* map of all registers, used for debugging */ | ||
1055 | |||
1056 | #ifdef HFC_REGISTER_DEBUG | ||
1057 | struct hfc_register_names { | ||
1058 | char *name; | ||
1059 | u_char reg; | ||
1060 | } hfc_register_names[] = { | ||
1061 | /* write registers */ | ||
1062 | {"R_CIRM", 0x00}, | ||
1063 | {"R_CTRL", 0x01}, | ||
1064 | {"R_BRG_PCM_CFG ", 0x02}, | ||
1065 | {"R_RAM_ADDR0", 0x08}, | ||
1066 | {"R_RAM_ADDR1", 0x09}, | ||
1067 | {"R_RAM_ADDR2", 0x0A}, | ||
1068 | {"R_FIRST_FIFO", 0x0B}, | ||
1069 | {"R_RAM_SZ", 0x0C}, | ||
1070 | {"R_FIFO_MD", 0x0D}, | ||
1071 | {"R_INC_RES_FIFO", 0x0E}, | ||
1072 | {"R_FIFO / R_FSM_IDX", 0x0F}, | ||
1073 | {"R_SLOT", 0x10}, | ||
1074 | {"R_IRQMSK_MISC", 0x11}, | ||
1075 | {"R_SCI_MSK", 0x12}, | ||
1076 | {"R_IRQ_CTRL", 0x13}, | ||
1077 | {"R_PCM_MD0", 0x14}, | ||
1078 | {"R_0x15", 0x15}, | ||
1079 | {"R_ST_SEL", 0x16}, | ||
1080 | {"R_ST_SYNC", 0x17}, | ||
1081 | {"R_CONF_EN", 0x18}, | ||
1082 | {"R_TI_WD", 0x1A}, | ||
1083 | {"R_BERT_WD_MD", 0x1B}, | ||
1084 | {"R_DTMF", 0x1C}, | ||
1085 | {"R_DTMF_N", 0x1D}, | ||
1086 | {"R_E1_XX_STA", 0x20}, | ||
1087 | {"R_LOS0", 0x22}, | ||
1088 | {"R_LOS1", 0x23}, | ||
1089 | {"R_RX0", 0x24}, | ||
1090 | {"R_RX_FR0", 0x25}, | ||
1091 | {"R_RX_FR1", 0x26}, | ||
1092 | {"R_TX0", 0x28}, | ||
1093 | {"R_TX1", 0x29}, | ||
1094 | {"R_TX_FR0", 0x2C}, | ||
1095 | {"R_TX_FR1", 0x2D}, | ||
1096 | {"R_TX_FR2", 0x2E}, | ||
1097 | {"R_JATT_ATT", 0x2F}, | ||
1098 | {"A_ST_xx_STA/R_RX_OFF", 0x30}, | ||
1099 | {"A_ST_CTRL0/R_SYNC_OUT", 0x31}, | ||
1100 | {"A_ST_CTRL1", 0x32}, | ||
1101 | {"A_ST_CTRL2", 0x33}, | ||
1102 | {"A_ST_SQ_WR", 0x34}, | ||
1103 | {"R_TX_OFF", 0x34}, | ||
1104 | {"R_SYNC_CTRL", 0x35}, | ||
1105 | {"A_ST_CLK_DLY", 0x37}, | ||
1106 | {"R_PWM0", 0x38}, | ||
1107 | {"R_PWM1", 0x39}, | ||
1108 | {"A_ST_B1_TX", 0x3C}, | ||
1109 | {"A_ST_B2_TX", 0x3D}, | ||
1110 | {"A_ST_D_TX", 0x3E}, | ||
1111 | {"R_GPIO_OUT0", 0x40}, | ||
1112 | {"R_GPIO_OUT1", 0x41}, | ||
1113 | {"R_GPIO_EN0", 0x42}, | ||
1114 | {"R_GPIO_EN1", 0x43}, | ||
1115 | {"R_GPIO_SEL", 0x44}, | ||
1116 | {"R_BRG_CTRL", 0x45}, | ||
1117 | {"R_PWM_MD", 0x46}, | ||
1118 | {"R_BRG_MD", 0x47}, | ||
1119 | {"R_BRG_TIM0", 0x48}, | ||
1120 | {"R_BRG_TIM1", 0x49}, | ||
1121 | {"R_BRG_TIM2", 0x4A}, | ||
1122 | {"R_BRG_TIM3", 0x4B}, | ||
1123 | {"R_BRG_TIM_SEL01", 0x4C}, | ||
1124 | {"R_BRG_TIM_SEL23", 0x4D}, | ||
1125 | {"R_BRG_TIM_SEL45", 0x4E}, | ||
1126 | {"R_BRG_TIM_SEL67", 0x4F}, | ||
1127 | {"A_FIFO_DATA0-2", 0x80}, | ||
1128 | {"A_FIFO_DATA0-2_NOINC", 0x84}, | ||
1129 | {"R_RAM_DATA", 0xC0}, | ||
1130 | {"A_SL_CFG", 0xD0}, | ||
1131 | {"A_CONF", 0xD1}, | ||
1132 | {"A_CH_MSK", 0xF4}, | ||
1133 | {"A_CON_HDLC", 0xFA}, | ||
1134 | {"A_SUBCH_CFG", 0xFB}, | ||
1135 | {"A_CHANNEL", 0xFC}, | ||
1136 | {"A_FIFO_SEQ", 0xFD}, | ||
1137 | {"A_IRQ_MSK", 0xFF}, | ||
1138 | {NULL, 0}, | ||
1139 | |||
1140 | /* read registers */ | ||
1141 | {"A_Z1", 0x04}, | ||
1142 | {"A_Z1H", 0x05}, | ||
1143 | {"A_Z2", 0x06}, | ||
1144 | {"A_Z2H", 0x07}, | ||
1145 | {"A_F1", 0x0C}, | ||
1146 | {"A_F2", 0x0D}, | ||
1147 | {"R_IRQ_OVIEW", 0x10}, | ||
1148 | {"R_IRQ_MISC", 0x11}, | ||
1149 | {"R_IRQ_STATECH", 0x12}, | ||
1150 | {"R_CONF_OFLOW", 0x14}, | ||
1151 | {"R_RAM_USE", 0x15}, | ||
1152 | {"R_CHIP_ID", 0x16}, | ||
1153 | {"R_BERT_STA", 0x17}, | ||
1154 | {"R_F0_CNTL", 0x18}, | ||
1155 | {"R_F0_CNTH", 0x19}, | ||
1156 | {"R_BERT_ECL", 0x1A}, | ||
1157 | {"R_BERT_ECH", 0x1B}, | ||
1158 | {"R_STATUS", 0x1C}, | ||
1159 | {"R_CHIP_RV", 0x1F}, | ||
1160 | {"R_STATE", 0x20}, | ||
1161 | {"R_SYNC_STA", 0x24}, | ||
1162 | {"R_RX_SL0_0", 0x25}, | ||
1163 | {"R_RX_SL0_1", 0x26}, | ||
1164 | {"R_RX_SL0_2", 0x27}, | ||
1165 | {"R_JATT_DIR", 0x2b}, | ||
1166 | {"R_SLIP", 0x2c}, | ||
1167 | {"A_ST_RD_STA", 0x30}, | ||
1168 | {"R_FAS_ECL", 0x30}, | ||
1169 | {"R_FAS_ECH", 0x31}, | ||
1170 | {"R_VIO_ECL", 0x32}, | ||
1171 | {"R_VIO_ECH", 0x33}, | ||
1172 | {"R_CRC_ECL / A_ST_SQ_RD", 0x34}, | ||
1173 | {"R_CRC_ECH", 0x35}, | ||
1174 | {"R_E_ECL", 0x36}, | ||
1175 | {"R_E_ECH", 0x37}, | ||
1176 | {"R_SA6_SA13_ECL", 0x38}, | ||
1177 | {"R_SA6_SA13_ECH", 0x39}, | ||
1178 | {"R_SA6_SA23_ECL", 0x3A}, | ||
1179 | {"R_SA6_SA23_ECH", 0x3B}, | ||
1180 | {"A_ST_B1_RX", 0x3C}, | ||
1181 | {"A_ST_B2_RX", 0x3D}, | ||
1182 | {"A_ST_D_RX", 0x3E}, | ||
1183 | {"A_ST_E_RX", 0x3F}, | ||
1184 | {"R_GPIO_IN0", 0x40}, | ||
1185 | {"R_GPIO_IN1", 0x41}, | ||
1186 | {"R_GPI_IN0", 0x44}, | ||
1187 | {"R_GPI_IN1", 0x45}, | ||
1188 | {"R_GPI_IN2", 0x46}, | ||
1189 | {"R_GPI_IN3", 0x47}, | ||
1190 | {"A_FIFO_DATA0-2", 0x80}, | ||
1191 | {"A_FIFO_DATA0-2_NOINC", 0x84}, | ||
1192 | {"R_INT_DATA", 0x88}, | ||
1193 | {"R_RAM_DATA", 0xC0}, | ||
1194 | {"R_IRQ_FIFO_BL0", 0xC8}, | ||
1195 | {"R_IRQ_FIFO_BL1", 0xC9}, | ||
1196 | {"R_IRQ_FIFO_BL2", 0xCA}, | ||
1197 | {"R_IRQ_FIFO_BL3", 0xCB}, | ||
1198 | {"R_IRQ_FIFO_BL4", 0xCC}, | ||
1199 | {"R_IRQ_FIFO_BL5", 0xCD}, | ||
1200 | {"R_IRQ_FIFO_BL6", 0xCE}, | ||
1201 | {"R_IRQ_FIFO_BL7", 0xCF}, | ||
1202 | }; | ||
1203 | #endif /* HFC_REGISTER_DEBUG */ | ||
1204 | |||
diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h new file mode 100644 index 000000000000..fd2c9be6d849 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfc_pci.h | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * specific defines for CCD's HFC 2BDS0 PCI chips | ||
3 | * | ||
4 | * Author Werner Cornelius (werner@isdn4linux.de) | ||
5 | * | ||
6 | * Copyright 1999 by Werner Cornelius (werner@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 as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
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 | /* | ||
25 | * thresholds for transparent B-channel mode | ||
26 | * change mask and threshold simultaneously | ||
27 | */ | ||
28 | #define HFCPCI_BTRANS_THRESHOLD 128 | ||
29 | #define HFCPCI_BTRANS_MAX 256 | ||
30 | #define HFCPCI_BTRANS_THRESMASK 0x00 | ||
31 | |||
32 | /* defines for PCI config */ | ||
33 | #define PCI_ENA_MEMIO 0x02 | ||
34 | #define PCI_ENA_MASTER 0x04 | ||
35 | |||
36 | /* GCI/IOM bus monitor registers */ | ||
37 | #define HCFPCI_C_I 0x08 | ||
38 | #define HFCPCI_TRxR 0x0C | ||
39 | #define HFCPCI_MON1_D 0x28 | ||
40 | #define HFCPCI_MON2_D 0x2C | ||
41 | |||
42 | /* GCI/IOM bus timeslot registers */ | ||
43 | #define HFCPCI_B1_SSL 0x80 | ||
44 | #define HFCPCI_B2_SSL 0x84 | ||
45 | #define HFCPCI_AUX1_SSL 0x88 | ||
46 | #define HFCPCI_AUX2_SSL 0x8C | ||
47 | #define HFCPCI_B1_RSL 0x90 | ||
48 | #define HFCPCI_B2_RSL 0x94 | ||
49 | #define HFCPCI_AUX1_RSL 0x98 | ||
50 | #define HFCPCI_AUX2_RSL 0x9C | ||
51 | |||
52 | /* GCI/IOM bus data registers */ | ||
53 | #define HFCPCI_B1_D 0xA0 | ||
54 | #define HFCPCI_B2_D 0xA4 | ||
55 | #define HFCPCI_AUX1_D 0xA8 | ||
56 | #define HFCPCI_AUX2_D 0xAC | ||
57 | |||
58 | /* GCI/IOM bus configuration registers */ | ||
59 | #define HFCPCI_MST_EMOD 0xB4 | ||
60 | #define HFCPCI_MST_MODE 0xB8 | ||
61 | #define HFCPCI_CONNECT 0xBC | ||
62 | |||
63 | |||
64 | /* Interrupt and status registers */ | ||
65 | #define HFCPCI_FIFO_EN 0x44 | ||
66 | #define HFCPCI_TRM 0x48 | ||
67 | #define HFCPCI_B_MODE 0x4C | ||
68 | #define HFCPCI_CHIP_ID 0x58 | ||
69 | #define HFCPCI_CIRM 0x60 | ||
70 | #define HFCPCI_CTMT 0x64 | ||
71 | #define HFCPCI_INT_M1 0x68 | ||
72 | #define HFCPCI_INT_M2 0x6C | ||
73 | #define HFCPCI_INT_S1 0x78 | ||
74 | #define HFCPCI_INT_S2 0x7C | ||
75 | #define HFCPCI_STATUS 0x70 | ||
76 | |||
77 | /* S/T section registers */ | ||
78 | #define HFCPCI_STATES 0xC0 | ||
79 | #define HFCPCI_SCTRL 0xC4 | ||
80 | #define HFCPCI_SCTRL_E 0xC8 | ||
81 | #define HFCPCI_SCTRL_R 0xCC | ||
82 | #define HFCPCI_SQ 0xD0 | ||
83 | #define HFCPCI_CLKDEL 0xDC | ||
84 | #define HFCPCI_B1_REC 0xF0 | ||
85 | #define HFCPCI_B1_SEND 0xF0 | ||
86 | #define HFCPCI_B2_REC 0xF4 | ||
87 | #define HFCPCI_B2_SEND 0xF4 | ||
88 | #define HFCPCI_D_REC 0xF8 | ||
89 | #define HFCPCI_D_SEND 0xF8 | ||
90 | #define HFCPCI_E_REC 0xFC | ||
91 | |||
92 | |||
93 | /* bits in status register (READ) */ | ||
94 | #define HFCPCI_PCI_PROC 0x02 | ||
95 | #define HFCPCI_NBUSY 0x04 | ||
96 | #define HFCPCI_TIMER_ELAP 0x10 | ||
97 | #define HFCPCI_STATINT 0x20 | ||
98 | #define HFCPCI_FRAMEINT 0x40 | ||
99 | #define HFCPCI_ANYINT 0x80 | ||
100 | |||
101 | /* bits in CTMT (Write) */ | ||
102 | #define HFCPCI_CLTIMER 0x80 | ||
103 | #define HFCPCI_TIM3_125 0x04 | ||
104 | #define HFCPCI_TIM25 0x10 | ||
105 | #define HFCPCI_TIM50 0x14 | ||
106 | #define HFCPCI_TIM400 0x18 | ||
107 | #define HFCPCI_TIM800 0x1C | ||
108 | #define HFCPCI_AUTO_TIMER 0x20 | ||
109 | #define HFCPCI_TRANSB2 0x02 | ||
110 | #define HFCPCI_TRANSB1 0x01 | ||
111 | |||
112 | /* bits in CIRM (Write) */ | ||
113 | #define HFCPCI_AUX_MSK 0x07 | ||
114 | #define HFCPCI_RESET 0x08 | ||
115 | #define HFCPCI_B1_REV 0x40 | ||
116 | #define HFCPCI_B2_REV 0x80 | ||
117 | |||
118 | /* bits in INT_M1 and INT_S1 */ | ||
119 | #define HFCPCI_INTS_B1TRANS 0x01 | ||
120 | #define HFCPCI_INTS_B2TRANS 0x02 | ||
121 | #define HFCPCI_INTS_DTRANS 0x04 | ||
122 | #define HFCPCI_INTS_B1REC 0x08 | ||
123 | #define HFCPCI_INTS_B2REC 0x10 | ||
124 | #define HFCPCI_INTS_DREC 0x20 | ||
125 | #define HFCPCI_INTS_L1STATE 0x40 | ||
126 | #define HFCPCI_INTS_TIMER 0x80 | ||
127 | |||
128 | /* bits in INT_M2 */ | ||
129 | #define HFCPCI_PROC_TRANS 0x01 | ||
130 | #define HFCPCI_GCI_I_CHG 0x02 | ||
131 | #define HFCPCI_GCI_MON_REC 0x04 | ||
132 | #define HFCPCI_IRQ_ENABLE 0x08 | ||
133 | #define HFCPCI_PMESEL 0x80 | ||
134 | |||
135 | /* bits in STATES */ | ||
136 | #define HFCPCI_STATE_MSK 0x0F | ||
137 | #define HFCPCI_LOAD_STATE 0x10 | ||
138 | #define HFCPCI_ACTIVATE 0x20 | ||
139 | #define HFCPCI_DO_ACTION 0x40 | ||
140 | #define HFCPCI_NT_G2_G3 0x80 | ||
141 | |||
142 | /* bits in HFCD_MST_MODE */ | ||
143 | #define HFCPCI_MASTER 0x01 | ||
144 | #define HFCPCI_SLAVE 0x00 | ||
145 | #define HFCPCI_F0IO_POSITIV 0x02 | ||
146 | #define HFCPCI_F0_NEGATIV 0x04 | ||
147 | #define HFCPCI_F0_2C4 0x08 | ||
148 | /* remaining bits are for codecs control */ | ||
149 | |||
150 | /* bits in HFCD_SCTRL */ | ||
151 | #define SCTRL_B1_ENA 0x01 | ||
152 | #define SCTRL_B2_ENA 0x02 | ||
153 | #define SCTRL_MODE_TE 0x00 | ||
154 | #define SCTRL_MODE_NT 0x04 | ||
155 | #define SCTRL_LOW_PRIO 0x08 | ||
156 | #define SCTRL_SQ_ENA 0x10 | ||
157 | #define SCTRL_TEST 0x20 | ||
158 | #define SCTRL_NONE_CAP 0x40 | ||
159 | #define SCTRL_PWR_DOWN 0x80 | ||
160 | |||
161 | /* bits in SCTRL_E */ | ||
162 | #define HFCPCI_AUTO_AWAKE 0x01 | ||
163 | #define HFCPCI_DBIT_1 0x04 | ||
164 | #define HFCPCI_IGNORE_COL 0x08 | ||
165 | #define HFCPCI_CHG_B1_B2 0x80 | ||
166 | |||
167 | /* bits in FIFO_EN register */ | ||
168 | #define HFCPCI_FIFOEN_B1 0x03 | ||
169 | #define HFCPCI_FIFOEN_B2 0x0C | ||
170 | #define HFCPCI_FIFOEN_DTX 0x10 | ||
171 | #define HFCPCI_FIFOEN_B1TX 0x01 | ||
172 | #define HFCPCI_FIFOEN_B1RX 0x02 | ||
173 | #define HFCPCI_FIFOEN_B2TX 0x04 | ||
174 | #define HFCPCI_FIFOEN_B2RX 0x08 | ||
175 | |||
176 | |||
177 | /* definitions of fifo memory area */ | ||
178 | #define MAX_D_FRAMES 15 | ||
179 | #define MAX_B_FRAMES 31 | ||
180 | #define B_SUB_VAL 0x200 | ||
181 | #define B_FIFO_SIZE (0x2000 - B_SUB_VAL) | ||
182 | #define D_FIFO_SIZE 512 | ||
183 | #define D_FREG_MASK 0xF | ||
184 | |||
185 | struct zt { | ||
186 | unsigned short z1; /* Z1 pointer 16 Bit */ | ||
187 | unsigned short z2; /* Z2 pointer 16 Bit */ | ||
188 | }; | ||
189 | |||
190 | struct dfifo { | ||
191 | u_char data[D_FIFO_SIZE]; /* FIFO data space */ | ||
192 | u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */ | ||
193 | u_char f1, f2; /* f pointers */ | ||
194 | u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */ | ||
195 | /* mask index with D_FREG_MASK for access */ | ||
196 | struct zt za[MAX_D_FRAMES+1]; | ||
197 | u_char fill3[0x4000-0x2100]; /* align 16K */ | ||
198 | }; | ||
199 | |||
200 | struct bzfifo { | ||
201 | struct zt za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */ | ||
202 | u_char f1, f2; /* f pointers */ | ||
203 | u_char fill[0x2100-0x2082]; /* alignment */ | ||
204 | }; | ||
205 | |||
206 | |||
207 | union fifo_area { | ||
208 | struct { | ||
209 | struct dfifo d_tx; /* D-send channel */ | ||
210 | struct dfifo d_rx; /* D-receive channel */ | ||
211 | } d_chan; | ||
212 | struct { | ||
213 | u_char fill1[0x200]; | ||
214 | u_char txdat_b1[B_FIFO_SIZE]; | ||
215 | struct bzfifo txbz_b1; | ||
216 | struct bzfifo txbz_b2; | ||
217 | u_char txdat_b2[B_FIFO_SIZE]; | ||
218 | u_char fill2[D_FIFO_SIZE]; | ||
219 | u_char rxdat_b1[B_FIFO_SIZE]; | ||
220 | struct bzfifo rxbz_b1; | ||
221 | struct bzfifo rxbz_b2; | ||
222 | u_char rxdat_b2[B_FIFO_SIZE]; | ||
223 | } b_chans; | ||
224 | u_char fill[32768]; | ||
225 | }; | ||
226 | |||
227 | #define Write_hfc(a, b, c) (writeb(c, (a->hw.pci_io)+b)) | ||
228 | #define Read_hfc(a, b) (readb((a->hw.pci_io)+b)) | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c new file mode 100644 index 000000000000..2649ea55a9e8 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
@@ -0,0 +1,5320 @@ | |||
1 | /* | ||
2 | * hfcmulti.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards | ||
3 | * | ||
4 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * ported to mqueue mechanism: | ||
6 | * Peter Sprenger (sprengermoving-bytes.de) | ||
7 | * | ||
8 | * inspired by existing hfc-pci driver: | ||
9 | * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) | ||
10 | * Copyright 2008 by Karsten Keil (kkeil@suse.de) | ||
11 | * Copyright 2008 by Andreas Eversberg (jolly@eversberg.eu) | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2, or (at your option) | ||
16 | * any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | * | ||
27 | * | ||
28 | * Thanks to Cologne Chip AG for this great controller! | ||
29 | */ | ||
30 | |||
31 | /* | ||
32 | * module parameters: | ||
33 | * type: | ||
34 | * By default (0), the card is automatically detected. | ||
35 | * Or use the following combinations: | ||
36 | * Bit 0-7 = 0x00001 = HFC-E1 (1 port) | ||
37 | * or Bit 0-7 = 0x00004 = HFC-4S (4 ports) | ||
38 | * or Bit 0-7 = 0x00008 = HFC-8S (8 ports) | ||
39 | * Bit 8 = 0x00100 = uLaw (instead of aLaw) | ||
40 | * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware | ||
41 | * Bit 10 = spare | ||
42 | * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwhise auto) | ||
43 | * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwhise auto) | ||
44 | * Bit 13 = spare | ||
45 | * Bit 14 = 0x04000 = Use external ram (128K) | ||
46 | * Bit 15 = 0x08000 = Use external ram (512K) | ||
47 | * Bit 16 = 0x10000 = Use 64 timeslots instead of 32 | ||
48 | * or Bit 17 = 0x20000 = Use 128 timeslots instead of anything else | ||
49 | * Bit 18 = spare | ||
50 | * Bit 19 = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog) | ||
51 | * (all other bits are reserved and shall be 0) | ||
52 | * example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM | ||
53 | * bus (PCM master) | ||
54 | * | ||
55 | * port: (optional or required for all ports on all installed cards) | ||
56 | * HFC-4S/HFC-8S only bits: | ||
57 | * Bit 0 = 0x001 = Use master clock for this S/T interface | ||
58 | * (ony once per chip). | ||
59 | * Bit 1 = 0x002 = transmitter line setup (non capacitive mode) | ||
60 | * Don't use this unless you know what you are doing! | ||
61 | * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing) | ||
62 | * example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock | ||
63 | * received from port 1 | ||
64 | * | ||
65 | * HFC-E1 only bits: | ||
66 | * Bit 0 = 0x0001 = interface: 0=copper, 1=optical | ||
67 | * Bit 1 = 0x0002 = reserved (later for 32 B-channels transparent mode) | ||
68 | * Bit 2 = 0x0004 = Report LOS | ||
69 | * Bit 3 = 0x0008 = Report AIS | ||
70 | * Bit 4 = 0x0010 = Report SLIP | ||
71 | * Bit 5 = 0x0020 = Report RDI | ||
72 | * Bit 8 = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame | ||
73 | * mode instead. | ||
74 | * Bit 9 = 0x0200 = Force get clock from interface, even in NT mode. | ||
75 | * or Bit 10 = 0x0400 = Force put clock to interface, even in TE mode. | ||
76 | * Bit 11 = 0x0800 = Use direct RX clock for PCM sync rather than PLL. | ||
77 | * (E1 only) | ||
78 | * Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0 | ||
79 | * for default. | ||
80 | * (all other bits are reserved and shall be 0) | ||
81 | * | ||
82 | * debug: | ||
83 | * NOTE: only one debug value must be given for all cards | ||
84 | * enable debugging (see hfc_multi.h for debug options) | ||
85 | * | ||
86 | * poll: | ||
87 | * NOTE: only one poll value must be given for all cards | ||
88 | * Give the number of samples for each fifo process. | ||
89 | * By default 128 is used. Decrease to reduce delay, increase to | ||
90 | * reduce cpu load. If unsure, don't mess with it! | ||
91 | * Valid is 8, 16, 32, 64, 128, 256. | ||
92 | * | ||
93 | * pcm: | ||
94 | * NOTE: only one pcm value must be given for every card. | ||
95 | * The PCM bus id tells the mISDNdsp module about the connected PCM bus. | ||
96 | * By default (0), the PCM bus id is 100 for the card that is PCM master. | ||
97 | * If multiple cards are PCM master (because they are not interconnected), | ||
98 | * each card with PCM master will have increasing PCM id. | ||
99 | * All PCM busses with the same ID are expected to be connected and have | ||
100 | * common time slots slots. | ||
101 | * Only one chip of the PCM bus must be master, the others slave. | ||
102 | * -1 means no support of PCM bus not even. | ||
103 | * Omit this value, if all cards are interconnected or none is connected. | ||
104 | * If unsure, don't give this parameter. | ||
105 | * | ||
106 | * dslot: | ||
107 | * NOTE: only one poll value must be given for every card. | ||
108 | * Also this value must be given for non-E1 cards. If omitted, the E1 | ||
109 | * card has D-channel on time slot 16, which is default. | ||
110 | * If 1..15 or 17..31, an alternate time slot is used for D-channel. | ||
111 | * In this case, the application must be able to handle this. | ||
112 | * If -1 is given, the D-channel is disabled and all 31 slots can be used | ||
113 | * for B-channel. (only for specific applications) | ||
114 | * If you don't know how to use it, you don't need it! | ||
115 | * | ||
116 | * iomode: | ||
117 | * NOTE: only one mode value must be given for every card. | ||
118 | * -> See hfc_multi.h for HFC_IO_MODE_* values | ||
119 | * By default, the IO mode is pci memory IO (MEMIO). | ||
120 | * Some cards requre specific IO mode, so it cannot be changed. | ||
121 | * It may be usefull to set IO mode to register io (REGIO) to solve | ||
122 | * PCI bridge problems. | ||
123 | * If unsure, don't give this parameter. | ||
124 | * | ||
125 | * clockdelay_nt: | ||
126 | * NOTE: only one clockdelay_nt value must be given once for all cards. | ||
127 | * Give the value of the clock control register (A_ST_CLK_DLY) | ||
128 | * of the S/T interfaces in NT mode. | ||
129 | * This register is needed for the TBR3 certification, so don't change it. | ||
130 | * | ||
131 | * clockdelay_te: | ||
132 | * NOTE: only one clockdelay_te value must be given once | ||
133 | * Give the value of the clock control register (A_ST_CLK_DLY) | ||
134 | * of the S/T interfaces in TE mode. | ||
135 | * This register is needed for the TBR3 certification, so don't change it. | ||
136 | */ | ||
137 | |||
138 | /* | ||
139 | * debug register access (never use this, it will flood your system log) | ||
140 | * #define HFC_REGISTER_DEBUG | ||
141 | */ | ||
142 | |||
143 | static const char *hfcmulti_revision = "2.00"; | ||
144 | |||
145 | #include <linux/module.h> | ||
146 | #include <linux/pci.h> | ||
147 | #include <linux/delay.h> | ||
148 | #include <linux/mISDNhw.h> | ||
149 | #include <linux/mISDNdsp.h> | ||
150 | |||
151 | /* | ||
152 | #define IRQCOUNT_DEBUG | ||
153 | #define IRQ_DEBUG | ||
154 | */ | ||
155 | |||
156 | #include "hfc_multi.h" | ||
157 | #ifdef ECHOPREP | ||
158 | #include "gaintab.h" | ||
159 | #endif | ||
160 | |||
161 | #define MAX_CARDS 8 | ||
162 | #define MAX_PORTS (8 * MAX_CARDS) | ||
163 | |||
164 | static LIST_HEAD(HFClist); | ||
165 | static spinlock_t HFClock; /* global hfc list lock */ | ||
166 | |||
167 | static void ph_state_change(struct dchannel *); | ||
168 | static void (*hfc_interrupt)(void); | ||
169 | static void (*register_interrupt)(void); | ||
170 | static int (*unregister_interrupt)(void); | ||
171 | static int interrupt_registered; | ||
172 | |||
173 | static struct hfc_multi *syncmaster; | ||
174 | int plxsd_master; /* if we have a master card (yet) */ | ||
175 | static spinlock_t plx_lock; /* may not acquire other lock inside */ | ||
176 | EXPORT_SYMBOL(plx_lock); | ||
177 | |||
178 | #define TYP_E1 1 | ||
179 | #define TYP_4S 4 | ||
180 | #define TYP_8S 8 | ||
181 | |||
182 | static int poll_timer = 6; /* default = 128 samples = 16ms */ | ||
183 | /* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */ | ||
184 | static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; | ||
185 | #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ | ||
186 | #define CLKDEL_NT 0x6c /* CLKDEL in NT mode | ||
187 | (0x60 MUST be included!) */ | ||
188 | static u_char silence = 0xff; /* silence by LAW */ | ||
189 | |||
190 | #define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ | ||
191 | #define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ | ||
192 | #define DIP_E1 0x3 /* DIP Switches for Beronet E1 cards */ | ||
193 | |||
194 | /* | ||
195 | * module stuff | ||
196 | */ | ||
197 | |||
198 | static uint type[MAX_CARDS]; | ||
199 | static uint pcm[MAX_CARDS]; | ||
200 | static uint dslot[MAX_CARDS]; | ||
201 | static uint iomode[MAX_CARDS]; | ||
202 | static uint port[MAX_PORTS]; | ||
203 | static uint debug; | ||
204 | static uint poll; | ||
205 | static uint timer; | ||
206 | static uint clockdelay_te = CLKDEL_TE; | ||
207 | static uint clockdelay_nt = CLKDEL_NT; | ||
208 | |||
209 | static int HFC_cnt, Port_cnt, PCM_cnt = 99; | ||
210 | |||
211 | MODULE_AUTHOR("Andreas Eversberg"); | ||
212 | MODULE_LICENSE("GPL"); | ||
213 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
214 | module_param(poll, uint, S_IRUGO | S_IWUSR); | ||
215 | module_param(timer, uint, S_IRUGO | S_IWUSR); | ||
216 | module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); | ||
217 | module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); | ||
218 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | ||
219 | module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR); | ||
220 | module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR); | ||
221 | module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); | ||
222 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | ||
223 | |||
224 | #ifdef HFC_REGISTER_DEBUG | ||
225 | #define HFC_outb(hc, reg, val) \ | ||
226 | (hc->HFC_outb(hc, reg, val, __func__, __LINE__)) | ||
227 | #define HFC_outb_nodebug(hc, reg, val) \ | ||
228 | (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__)) | ||
229 | #define HFC_inb(hc, reg) \ | ||
230 | (hc->HFC_inb(hc, reg, __func__, __LINE__)) | ||
231 | #define HFC_inb_nodebug(hc, reg) \ | ||
232 | (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__)) | ||
233 | #define HFC_inw(hc, reg) \ | ||
234 | (hc->HFC_inw(hc, reg, __func__, __LINE__)) | ||
235 | #define HFC_inw_nodebug(hc, reg) \ | ||
236 | (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__)) | ||
237 | #define HFC_wait(hc) \ | ||
238 | (hc->HFC_wait(hc, __func__, __LINE__)) | ||
239 | #define HFC_wait_nodebug(hc) \ | ||
240 | (hc->HFC_wait_nodebug(hc, __func__, __LINE__)) | ||
241 | #else | ||
242 | #define HFC_outb(hc, reg, val) (hc->HFC_outb(hc, reg, val)) | ||
243 | #define HFC_outb_nodebug(hc, reg, val) (hc->HFC_outb_nodebug(hc, reg, val)) | ||
244 | #define HFC_inb(hc, reg) (hc->HFC_inb(hc, reg)) | ||
245 | #define HFC_inb_nodebug(hc, reg) (hc->HFC_inb_nodebug(hc, reg)) | ||
246 | #define HFC_inw(hc, reg) (hc->HFC_inw(hc, reg)) | ||
247 | #define HFC_inw_nodebug(hc, reg) (hc->HFC_inw_nodebug(hc, reg)) | ||
248 | #define HFC_wait(hc) (hc->HFC_wait(hc)) | ||
249 | #define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) | ||
250 | #endif | ||
251 | |||
252 | /* HFC_IO_MODE_PCIMEM */ | ||
253 | static void | ||
254 | #ifdef HFC_REGISTER_DEBUG | ||
255 | HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, | ||
256 | const char *function, int line) | ||
257 | #else | ||
258 | HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) | ||
259 | #endif | ||
260 | { | ||
261 | writeb(val, (hc->pci_membase)+reg); | ||
262 | } | ||
263 | static u_char | ||
264 | #ifdef HFC_REGISTER_DEBUG | ||
265 | HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
266 | #else | ||
267 | HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) | ||
268 | #endif | ||
269 | { | ||
270 | return readb((hc->pci_membase)+reg); | ||
271 | } | ||
272 | static u_short | ||
273 | #ifdef HFC_REGISTER_DEBUG | ||
274 | HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
275 | #else | ||
276 | HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) | ||
277 | #endif | ||
278 | { | ||
279 | return readw((hc->pci_membase)+reg); | ||
280 | } | ||
281 | static void | ||
282 | #ifdef HFC_REGISTER_DEBUG | ||
283 | HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) | ||
284 | #else | ||
285 | HFC_wait_pcimem(struct hfc_multi *hc) | ||
286 | #endif | ||
287 | { | ||
288 | while (readb((hc->pci_membase)+R_STATUS) & V_BUSY); | ||
289 | } | ||
290 | |||
291 | /* HFC_IO_MODE_REGIO */ | ||
292 | static void | ||
293 | #ifdef HFC_REGISTER_DEBUG | ||
294 | HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, | ||
295 | const char *function, int line) | ||
296 | #else | ||
297 | HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) | ||
298 | #endif | ||
299 | { | ||
300 | outb(reg, (hc->pci_iobase)+4); | ||
301 | outb(val, hc->pci_iobase); | ||
302 | } | ||
303 | static u_char | ||
304 | #ifdef HFC_REGISTER_DEBUG | ||
305 | HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
306 | #else | ||
307 | HFC_inb_regio(struct hfc_multi *hc, u_char reg) | ||
308 | #endif | ||
309 | { | ||
310 | outb(reg, (hc->pci_iobase)+4); | ||
311 | return inb(hc->pci_iobase); | ||
312 | } | ||
313 | static u_short | ||
314 | #ifdef HFC_REGISTER_DEBUG | ||
315 | HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
316 | #else | ||
317 | HFC_inw_regio(struct hfc_multi *hc, u_char reg) | ||
318 | #endif | ||
319 | { | ||
320 | outb(reg, (hc->pci_iobase)+4); | ||
321 | return inw(hc->pci_iobase); | ||
322 | } | ||
323 | static void | ||
324 | #ifdef HFC_REGISTER_DEBUG | ||
325 | HFC_wait_regio(struct hfc_multi *hc, const char *function, int line) | ||
326 | #else | ||
327 | HFC_wait_regio(struct hfc_multi *hc) | ||
328 | #endif | ||
329 | { | ||
330 | outb(R_STATUS, (hc->pci_iobase)+4); | ||
331 | while (inb(hc->pci_iobase) & V_BUSY); | ||
332 | } | ||
333 | |||
334 | #ifdef HFC_REGISTER_DEBUG | ||
335 | static void | ||
336 | HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, | ||
337 | const char *function, int line) | ||
338 | { | ||
339 | char regname[256] = "", bits[9] = "xxxxxxxx"; | ||
340 | int i; | ||
341 | |||
342 | i = -1; | ||
343 | while (hfc_register_names[++i].name) { | ||
344 | if (hfc_register_names[i].reg == reg) | ||
345 | strcat(regname, hfc_register_names[i].name); | ||
346 | } | ||
347 | if (regname[0] == '\0') | ||
348 | strcpy(regname, "register"); | ||
349 | |||
350 | bits[7] = '0'+(!!(val&1)); | ||
351 | bits[6] = '0'+(!!(val&2)); | ||
352 | bits[5] = '0'+(!!(val&4)); | ||
353 | bits[4] = '0'+(!!(val&8)); | ||
354 | bits[3] = '0'+(!!(val&16)); | ||
355 | bits[2] = '0'+(!!(val&32)); | ||
356 | bits[1] = '0'+(!!(val&64)); | ||
357 | bits[0] = '0'+(!!(val&128)); | ||
358 | printk(KERN_DEBUG | ||
359 | "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", | ||
360 | hc->id, reg, regname, val, bits, function, line); | ||
361 | HFC_outb_nodebug(hc, reg, val); | ||
362 | } | ||
363 | static u_char | ||
364 | HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
365 | { | ||
366 | char regname[256] = "", bits[9] = "xxxxxxxx"; | ||
367 | u_char val = HFC_inb_nodebug(hc, reg); | ||
368 | int i; | ||
369 | |||
370 | i = 0; | ||
371 | while (hfc_register_names[i++].name) | ||
372 | ; | ||
373 | while (hfc_register_names[++i].name) { | ||
374 | if (hfc_register_names[i].reg == reg) | ||
375 | strcat(regname, hfc_register_names[i].name); | ||
376 | } | ||
377 | if (regname[0] == '\0') | ||
378 | strcpy(regname, "register"); | ||
379 | |||
380 | bits[7] = '0'+(!!(val&1)); | ||
381 | bits[6] = '0'+(!!(val&2)); | ||
382 | bits[5] = '0'+(!!(val&4)); | ||
383 | bits[4] = '0'+(!!(val&8)); | ||
384 | bits[3] = '0'+(!!(val&16)); | ||
385 | bits[2] = '0'+(!!(val&32)); | ||
386 | bits[1] = '0'+(!!(val&64)); | ||
387 | bits[0] = '0'+(!!(val&128)); | ||
388 | printk(KERN_DEBUG | ||
389 | "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", | ||
390 | hc->id, reg, regname, val, bits, function, line); | ||
391 | return val; | ||
392 | } | ||
393 | static u_short | ||
394 | HFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
395 | { | ||
396 | char regname[256] = ""; | ||
397 | u_short val = HFC_inw_nodebug(hc, reg); | ||
398 | int i; | ||
399 | |||
400 | i = 0; | ||
401 | while (hfc_register_names[i++].name) | ||
402 | ; | ||
403 | while (hfc_register_names[++i].name) { | ||
404 | if (hfc_register_names[i].reg == reg) | ||
405 | strcat(regname, hfc_register_names[i].name); | ||
406 | } | ||
407 | if (regname[0] == '\0') | ||
408 | strcpy(regname, "register"); | ||
409 | |||
410 | printk(KERN_DEBUG | ||
411 | "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n", | ||
412 | hc->id, reg, regname, val, function, line); | ||
413 | return val; | ||
414 | } | ||
415 | static void | ||
416 | HFC_wait_debug(struct hfc_multi *hc, const char *function, int line) | ||
417 | { | ||
418 | printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n", | ||
419 | hc->id, function, line); | ||
420 | HFC_wait_nodebug(hc); | ||
421 | } | ||
422 | #endif | ||
423 | |||
424 | /* write fifo data (REGIO) */ | ||
425 | void | ||
426 | write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) | ||
427 | { | ||
428 | outb(A_FIFO_DATA0, (hc->pci_iobase)+4); | ||
429 | while (len>>2) { | ||
430 | outl(*(u32 *)data, hc->pci_iobase); | ||
431 | data += 4; | ||
432 | len -= 4; | ||
433 | } | ||
434 | while (len>>1) { | ||
435 | outw(*(u16 *)data, hc->pci_iobase); | ||
436 | data += 2; | ||
437 | len -= 2; | ||
438 | } | ||
439 | while (len) { | ||
440 | outb(*data, hc->pci_iobase); | ||
441 | data++; | ||
442 | len--; | ||
443 | } | ||
444 | } | ||
445 | /* write fifo data (PCIMEM) */ | ||
446 | void | ||
447 | write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) | ||
448 | { | ||
449 | while (len>>2) { | ||
450 | writel(*(u32 *)data, (hc->pci_membase)+A_FIFO_DATA0); | ||
451 | data += 4; | ||
452 | len -= 4; | ||
453 | } | ||
454 | while (len>>1) { | ||
455 | writew(*(u16 *)data, (hc->pci_membase)+A_FIFO_DATA0); | ||
456 | data += 2; | ||
457 | len -= 2; | ||
458 | } | ||
459 | while (len) { | ||
460 | writeb(*data, (hc->pci_membase)+A_FIFO_DATA0); | ||
461 | data++; | ||
462 | len--; | ||
463 | } | ||
464 | } | ||
465 | /* read fifo data (REGIO) */ | ||
466 | void | ||
467 | read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) | ||
468 | { | ||
469 | outb(A_FIFO_DATA0, (hc->pci_iobase)+4); | ||
470 | while (len>>2) { | ||
471 | *(u32 *)data = inl(hc->pci_iobase); | ||
472 | data += 4; | ||
473 | len -= 4; | ||
474 | } | ||
475 | while (len>>1) { | ||
476 | *(u16 *)data = inw(hc->pci_iobase); | ||
477 | data += 2; | ||
478 | len -= 2; | ||
479 | } | ||
480 | while (len) { | ||
481 | *data = inb(hc->pci_iobase); | ||
482 | data++; | ||
483 | len--; | ||
484 | } | ||
485 | } | ||
486 | |||
487 | /* read fifo data (PCIMEM) */ | ||
488 | void | ||
489 | read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) | ||
490 | { | ||
491 | while (len>>2) { | ||
492 | *(u32 *)data = | ||
493 | readl((hc->pci_membase)+A_FIFO_DATA0); | ||
494 | data += 4; | ||
495 | len -= 4; | ||
496 | } | ||
497 | while (len>>1) { | ||
498 | *(u16 *)data = | ||
499 | readw((hc->pci_membase)+A_FIFO_DATA0); | ||
500 | data += 2; | ||
501 | len -= 2; | ||
502 | } | ||
503 | while (len) { | ||
504 | *data = readb((hc->pci_membase)+A_FIFO_DATA0); | ||
505 | data++; | ||
506 | len--; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | |||
511 | static void | ||
512 | enable_hwirq(struct hfc_multi *hc) | ||
513 | { | ||
514 | hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; | ||
515 | HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); | ||
516 | } | ||
517 | |||
518 | static void | ||
519 | disable_hwirq(struct hfc_multi *hc) | ||
520 | { | ||
521 | hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); | ||
522 | HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); | ||
523 | } | ||
524 | |||
525 | #define NUM_EC 2 | ||
526 | #define MAX_TDM_CHAN 32 | ||
527 | |||
528 | |||
529 | inline void | ||
530 | enablepcibridge(struct hfc_multi *c) | ||
531 | { | ||
532 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */ | ||
533 | } | ||
534 | |||
535 | inline void | ||
536 | disablepcibridge(struct hfc_multi *c) | ||
537 | { | ||
538 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */ | ||
539 | } | ||
540 | |||
541 | inline unsigned char | ||
542 | readpcibridge(struct hfc_multi *hc, unsigned char address) | ||
543 | { | ||
544 | unsigned short cipv; | ||
545 | unsigned char data; | ||
546 | |||
547 | if (!hc->pci_iobase) | ||
548 | return 0; | ||
549 | |||
550 | /* slow down a PCI read access by 1 PCI clock cycle */ | ||
551 | HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/ | ||
552 | |||
553 | if (address == 0) | ||
554 | cipv = 0x4000; | ||
555 | else | ||
556 | cipv = 0x5800; | ||
557 | |||
558 | /* select local bridge port address by writing to CIP port */ | ||
559 | /* data = HFC_inb(c, cipv); * was _io before */ | ||
560 | outw(cipv, hc->pci_iobase + 4); | ||
561 | data = inb(hc->pci_iobase); | ||
562 | |||
563 | /* restore R_CTRL for normal PCI read cycle speed */ | ||
564 | HFC_outb(hc, R_CTRL, 0x0); /* was _io before */ | ||
565 | |||
566 | return data; | ||
567 | } | ||
568 | |||
569 | inline void | ||
570 | writepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data) | ||
571 | { | ||
572 | unsigned short cipv; | ||
573 | unsigned int datav; | ||
574 | |||
575 | if (!hc->pci_iobase) | ||
576 | return; | ||
577 | |||
578 | if (address == 0) | ||
579 | cipv = 0x4000; | ||
580 | else | ||
581 | cipv = 0x5800; | ||
582 | |||
583 | /* select local bridge port address by writing to CIP port */ | ||
584 | outw(cipv, hc->pci_iobase + 4); | ||
585 | /* define a 32 bit dword with 4 identical bytes for write sequence */ | ||
586 | datav = data | ((__u32) data << 8) | ((__u32) data << 16) | | ||
587 | ((__u32) data << 24); | ||
588 | |||
589 | /* | ||
590 | * write this 32 bit dword to the bridge data port | ||
591 | * this will initiate a write sequence of up to 4 writes to the same | ||
592 | * address on the local bus interface the number of write accesses | ||
593 | * is undefined but >=1 and depends on the next PCI transaction | ||
594 | * during write sequence on the local bus | ||
595 | */ | ||
596 | outl(datav, hc->pci_iobase); | ||
597 | } | ||
598 | |||
599 | inline void | ||
600 | cpld_set_reg(struct hfc_multi *hc, unsigned char reg) | ||
601 | { | ||
602 | /* Do data pin read low byte */ | ||
603 | HFC_outb(hc, R_GPIO_OUT1, reg); | ||
604 | } | ||
605 | |||
606 | inline void | ||
607 | cpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val) | ||
608 | { | ||
609 | cpld_set_reg(hc, reg); | ||
610 | |||
611 | enablepcibridge(hc); | ||
612 | writepcibridge(hc, 1, val); | ||
613 | disablepcibridge(hc); | ||
614 | |||
615 | return; | ||
616 | } | ||
617 | |||
618 | inline unsigned char | ||
619 | cpld_read_reg(struct hfc_multi *hc, unsigned char reg) | ||
620 | { | ||
621 | unsigned char bytein; | ||
622 | |||
623 | cpld_set_reg(hc, reg); | ||
624 | |||
625 | /* Do data pin read low byte */ | ||
626 | HFC_outb(hc, R_GPIO_OUT1, reg); | ||
627 | |||
628 | enablepcibridge(hc); | ||
629 | bytein = readpcibridge(hc, 1); | ||
630 | disablepcibridge(hc); | ||
631 | |||
632 | return bytein; | ||
633 | } | ||
634 | |||
635 | inline void | ||
636 | vpm_write_address(struct hfc_multi *hc, unsigned short addr) | ||
637 | { | ||
638 | cpld_write_reg(hc, 0, 0xff & addr); | ||
639 | cpld_write_reg(hc, 1, 0x01 & (addr >> 8)); | ||
640 | } | ||
641 | |||
642 | inline unsigned short | ||
643 | vpm_read_address(struct hfc_multi *c) | ||
644 | { | ||
645 | unsigned short addr; | ||
646 | unsigned short highbit; | ||
647 | |||
648 | addr = cpld_read_reg(c, 0); | ||
649 | highbit = cpld_read_reg(c, 1); | ||
650 | |||
651 | addr = addr | (highbit << 8); | ||
652 | |||
653 | return addr & 0x1ff; | ||
654 | } | ||
655 | |||
656 | inline unsigned char | ||
657 | vpm_in(struct hfc_multi *c, int which, unsigned short addr) | ||
658 | { | ||
659 | unsigned char res; | ||
660 | |||
661 | vpm_write_address(c, addr); | ||
662 | |||
663 | if (!which) | ||
664 | cpld_set_reg(c, 2); | ||
665 | else | ||
666 | cpld_set_reg(c, 3); | ||
667 | |||
668 | enablepcibridge(c); | ||
669 | res = readpcibridge(c, 1); | ||
670 | disablepcibridge(c); | ||
671 | |||
672 | cpld_set_reg(c, 0); | ||
673 | |||
674 | return res; | ||
675 | } | ||
676 | |||
677 | inline void | ||
678 | vpm_out(struct hfc_multi *c, int which, unsigned short addr, | ||
679 | unsigned char data) | ||
680 | { | ||
681 | vpm_write_address(c, addr); | ||
682 | |||
683 | enablepcibridge(c); | ||
684 | |||
685 | if (!which) | ||
686 | cpld_set_reg(c, 2); | ||
687 | else | ||
688 | cpld_set_reg(c, 3); | ||
689 | |||
690 | writepcibridge(c, 1, data); | ||
691 | |||
692 | cpld_set_reg(c, 0); | ||
693 | |||
694 | disablepcibridge(c); | ||
695 | |||
696 | { | ||
697 | unsigned char regin; | ||
698 | regin = vpm_in(c, which, addr); | ||
699 | if (regin != data) | ||
700 | printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back " | ||
701 | "0x%x\n", data, addr, regin); | ||
702 | } | ||
703 | |||
704 | } | ||
705 | |||
706 | |||
707 | void | ||
708 | vpm_init(struct hfc_multi *wc) | ||
709 | { | ||
710 | unsigned char reg; | ||
711 | unsigned int mask; | ||
712 | unsigned int i, x, y; | ||
713 | unsigned int ver; | ||
714 | |||
715 | for (x = 0; x < NUM_EC; x++) { | ||
716 | /* Setup GPIO's */ | ||
717 | if (!x) { | ||
718 | ver = vpm_in(wc, x, 0x1a0); | ||
719 | printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver); | ||
720 | } | ||
721 | |||
722 | for (y = 0; y < 4; y++) { | ||
723 | vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ | ||
724 | vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ | ||
725 | vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ | ||
726 | } | ||
727 | |||
728 | /* Setup TDM path - sets fsync and tdm_clk as inputs */ | ||
729 | reg = vpm_in(wc, x, 0x1a3); /* misc_con */ | ||
730 | vpm_out(wc, x, 0x1a3, reg & ~2); | ||
731 | |||
732 | /* Setup Echo length (256 taps) */ | ||
733 | vpm_out(wc, x, 0x022, 1); | ||
734 | vpm_out(wc, x, 0x023, 0xff); | ||
735 | |||
736 | /* Setup timeslots */ | ||
737 | vpm_out(wc, x, 0x02f, 0x00); | ||
738 | mask = 0x02020202 << (x * 4); | ||
739 | |||
740 | /* Setup the tdm channel masks for all chips */ | ||
741 | for (i = 0; i < 4; i++) | ||
742 | vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff); | ||
743 | |||
744 | /* Setup convergence rate */ | ||
745 | printk(KERN_DEBUG "VPM: A-law mode\n"); | ||
746 | reg = 0x00 | 0x10 | 0x01; | ||
747 | vpm_out(wc, x, 0x20, reg); | ||
748 | printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg); | ||
749 | /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */ | ||
750 | |||
751 | vpm_out(wc, x, 0x24, 0x02); | ||
752 | reg = vpm_in(wc, x, 0x24); | ||
753 | printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg); | ||
754 | |||
755 | /* Initialize echo cans */ | ||
756 | for (i = 0; i < MAX_TDM_CHAN; i++) { | ||
757 | if (mask & (0x00000001 << i)) | ||
758 | vpm_out(wc, x, i, 0x00); | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * ARM arch at least disallows a udelay of | ||
763 | * more than 2ms... it gives a fake "__bad_udelay" | ||
764 | * reference at link-time. | ||
765 | * long delays in kernel code are pretty sucky anyway | ||
766 | * for now work around it using 5 x 2ms instead of 1 x 10ms | ||
767 | */ | ||
768 | |||
769 | udelay(2000); | ||
770 | udelay(2000); | ||
771 | udelay(2000); | ||
772 | udelay(2000); | ||
773 | udelay(2000); | ||
774 | |||
775 | /* Put in bypass mode */ | ||
776 | for (i = 0; i < MAX_TDM_CHAN; i++) { | ||
777 | if (mask & (0x00000001 << i)) | ||
778 | vpm_out(wc, x, i, 0x01); | ||
779 | } | ||
780 | |||
781 | /* Enable bypass */ | ||
782 | for (i = 0; i < MAX_TDM_CHAN; i++) { | ||
783 | if (mask & (0x00000001 << i)) | ||
784 | vpm_out(wc, x, 0x78 + i, 0x01); | ||
785 | } | ||
786 | |||
787 | } | ||
788 | } | ||
789 | |||
790 | void | ||
791 | vpm_check(struct hfc_multi *hctmp) | ||
792 | { | ||
793 | unsigned char gpi2; | ||
794 | |||
795 | gpi2 = HFC_inb(hctmp, R_GPI_IN2); | ||
796 | |||
797 | if ((gpi2 & 0x3) != 0x3) | ||
798 | printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); | ||
799 | } | ||
800 | |||
801 | |||
802 | /* | ||
803 | * Interface to enable/disable the HW Echocan | ||
804 | * | ||
805 | * these functions are called within a spin_lock_irqsave on | ||
806 | * the channel instance lock, so we are not disturbed by irqs | ||
807 | * | ||
808 | * we can later easily change the interface to make other | ||
809 | * things configurable, for now we configure the taps | ||
810 | * | ||
811 | */ | ||
812 | |||
813 | void | ||
814 | vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) | ||
815 | { | ||
816 | unsigned int timeslot; | ||
817 | unsigned int unit; | ||
818 | struct bchannel *bch = hc->chan[ch].bch; | ||
819 | #ifdef TXADJ | ||
820 | int txadj = -4; | ||
821 | struct sk_buff *skb; | ||
822 | #endif | ||
823 | if (hc->chan[ch].protocol != ISDN_P_B_RAW) | ||
824 | return; | ||
825 | |||
826 | if (!bch) | ||
827 | return; | ||
828 | |||
829 | #ifdef TXADJ | ||
830 | skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, | ||
831 | sizeof(int), &txadj, GFP_ATOMIC); | ||
832 | if (skb) | ||
833 | recv_Bchannel_skb(bch, skb); | ||
834 | #endif | ||
835 | |||
836 | timeslot = ((ch/4)*8) + ((ch%4)*4) + 1; | ||
837 | unit = ch % 4; | ||
838 | |||
839 | printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", | ||
840 | taps, timeslot); | ||
841 | |||
842 | vpm_out(hc, unit, timeslot, 0x7e); | ||
843 | } | ||
844 | |||
845 | void | ||
846 | vpm_echocan_off(struct hfc_multi *hc, int ch) | ||
847 | { | ||
848 | unsigned int timeslot; | ||
849 | unsigned int unit; | ||
850 | struct bchannel *bch = hc->chan[ch].bch; | ||
851 | #ifdef TXADJ | ||
852 | int txadj = 0; | ||
853 | struct sk_buff *skb; | ||
854 | #endif | ||
855 | |||
856 | if (hc->chan[ch].protocol != ISDN_P_B_RAW) | ||
857 | return; | ||
858 | |||
859 | if (!bch) | ||
860 | return; | ||
861 | |||
862 | #ifdef TXADJ | ||
863 | skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, | ||
864 | sizeof(int), &txadj, GFP_ATOMIC); | ||
865 | if (skb) | ||
866 | recv_Bchannel_skb(bch, skb); | ||
867 | #endif | ||
868 | |||
869 | timeslot = ((ch/4)*8) + ((ch%4)*4) + 1; | ||
870 | unit = ch % 4; | ||
871 | |||
872 | printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", | ||
873 | timeslot); | ||
874 | /* FILLME */ | ||
875 | vpm_out(hc, unit, timeslot, 0x01); | ||
876 | } | ||
877 | |||
878 | |||
879 | /* | ||
880 | * Speech Design resync feature | ||
881 | * NOTE: This is called sometimes outside interrupt handler. | ||
882 | * We must lock irqsave, so no other interrupt (other card) will occurr! | ||
883 | * Also multiple interrupts may nest, so must lock each access (lists, card)! | ||
884 | */ | ||
885 | static inline void | ||
886 | hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) | ||
887 | { | ||
888 | struct hfc_multi *hc, *next, *pcmmaster = 0; | ||
889 | u_int *plx_acc_32, pv; | ||
890 | u_long flags; | ||
891 | |||
892 | spin_lock_irqsave(&HFClock, flags); | ||
893 | spin_lock(&plx_lock); /* must be locked inside other locks */ | ||
894 | |||
895 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
896 | printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n", | ||
897 | __func__, syncmaster); | ||
898 | |||
899 | /* select new master */ | ||
900 | if (newmaster) { | ||
901 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
902 | printk(KERN_DEBUG "using provided controller\n"); | ||
903 | } else { | ||
904 | list_for_each_entry_safe(hc, next, &HFClist, list) { | ||
905 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
906 | if (hc->syncronized) { | ||
907 | newmaster = hc; | ||
908 | break; | ||
909 | } | ||
910 | } | ||
911 | } | ||
912 | } | ||
913 | |||
914 | /* Disable sync of all cards */ | ||
915 | list_for_each_entry_safe(hc, next, &HFClist, list) { | ||
916 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
917 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
918 | pv = readl(plx_acc_32); | ||
919 | pv &= ~PLX_SYNC_O_EN; | ||
920 | writel(pv, plx_acc_32); | ||
921 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { | ||
922 | pcmmaster = hc; | ||
923 | if (hc->type == 1) { | ||
924 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
925 | printk(KERN_DEBUG | ||
926 | "Schedule SYNC_I\n"); | ||
927 | hc->e1_resync |= 1; /* get SYNC_I */ | ||
928 | } | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | |||
933 | if (newmaster) { | ||
934 | hc = newmaster; | ||
935 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
936 | printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " | ||
937 | "interface.\n", hc->id, hc); | ||
938 | /* Enable new sync master */ | ||
939 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
940 | pv = readl(plx_acc_32); | ||
941 | pv |= PLX_SYNC_O_EN; | ||
942 | writel(pv, plx_acc_32); | ||
943 | /* switch to jatt PLL, if not disabled by RX_SYNC */ | ||
944 | if (hc->type == 1 && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { | ||
945 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
946 | printk(KERN_DEBUG "Schedule jatt PLL\n"); | ||
947 | hc->e1_resync |= 2; /* switch to jatt */ | ||
948 | } | ||
949 | } else { | ||
950 | if (pcmmaster) { | ||
951 | hc = pcmmaster; | ||
952 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
953 | printk(KERN_DEBUG | ||
954 | "id=%d (0x%p) = PCM master syncronized " | ||
955 | "with QUARTZ\n", hc->id, hc); | ||
956 | if (hc->type == 1) { | ||
957 | /* Use the crystal clock for the PCM | ||
958 | master card */ | ||
959 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
960 | printk(KERN_DEBUG | ||
961 | "Schedule QUARTZ for HFC-E1\n"); | ||
962 | hc->e1_resync |= 4; /* switch quartz */ | ||
963 | } else { | ||
964 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
965 | printk(KERN_DEBUG | ||
966 | "QUARTZ is automatically " | ||
967 | "enabled by HFC-%dS\n", hc->type); | ||
968 | } | ||
969 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
970 | pv = readl(plx_acc_32); | ||
971 | pv |= PLX_SYNC_O_EN; | ||
972 | writel(pv, plx_acc_32); | ||
973 | } else | ||
974 | if (!rm) | ||
975 | printk(KERN_ERR "%s no pcm master, this MUST " | ||
976 | "not happen!\n", __func__); | ||
977 | } | ||
978 | syncmaster = newmaster; | ||
979 | |||
980 | spin_unlock(&plx_lock); | ||
981 | spin_unlock_irqrestore(&HFClock, flags); | ||
982 | } | ||
983 | |||
984 | /* This must be called AND hc must be locked irqsave!!! */ | ||
985 | inline void | ||
986 | plxsd_checksync(struct hfc_multi *hc, int rm) | ||
987 | { | ||
988 | if (hc->syncronized) { | ||
989 | if (syncmaster == NULL) { | ||
990 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
991 | printk(KERN_WARNING "%s: GOT sync on card %d" | ||
992 | " (id=%d)\n", __func__, hc->id + 1, | ||
993 | hc->id); | ||
994 | hfcmulti_resync(hc, hc, rm); | ||
995 | } | ||
996 | } else { | ||
997 | if (syncmaster == hc) { | ||
998 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
999 | printk(KERN_WARNING "%s: LOST sync on card %d" | ||
1000 | " (id=%d)\n", __func__, hc->id + 1, | ||
1001 | hc->id); | ||
1002 | hfcmulti_resync(hc, NULL, rm); | ||
1003 | } | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /* | ||
1009 | * free hardware resources used by driver | ||
1010 | */ | ||
1011 | static void | ||
1012 | release_io_hfcmulti(struct hfc_multi *hc) | ||
1013 | { | ||
1014 | u_int *plx_acc_32, pv; | ||
1015 | u_long plx_flags; | ||
1016 | |||
1017 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1018 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
1019 | |||
1020 | /* soft reset also masks all interrupts */ | ||
1021 | hc->hw.r_cirm |= V_SRES; | ||
1022 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
1023 | udelay(1000); | ||
1024 | hc->hw.r_cirm &= ~V_SRES; | ||
1025 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
1026 | udelay(1000); /* instead of 'wait' that may cause locking */ | ||
1027 | |||
1028 | /* release Speech Design card, if PLX was initialized */ | ||
1029 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) { | ||
1030 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
1031 | printk(KERN_DEBUG "%s: release PLXSD card %d\n", | ||
1032 | __func__, hc->id + 1); | ||
1033 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
1034 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
1035 | writel(PLX_GPIOC_INIT, plx_acc_32); | ||
1036 | pv = readl(plx_acc_32); | ||
1037 | /* Termination off */ | ||
1038 | pv &= ~PLX_TERM_ON; | ||
1039 | /* Disconnect the PCM */ | ||
1040 | pv |= PLX_SLAVE_EN_N; | ||
1041 | pv &= ~PLX_MASTER_EN; | ||
1042 | pv &= ~PLX_SYNC_O_EN; | ||
1043 | /* Put the DSP in Reset */ | ||
1044 | pv &= ~PLX_DSP_RES_N; | ||
1045 | writel(pv, plx_acc_32); | ||
1046 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1047 | printk(KERN_WARNING "%s: PCM off: PLX_GPIO=%x\n", | ||
1048 | __func__, pv); | ||
1049 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
1050 | } | ||
1051 | |||
1052 | /* disable memory mapped ports / io ports */ | ||
1053 | test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ | ||
1054 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); | ||
1055 | if (hc->pci_membase) | ||
1056 | iounmap((void *)hc->pci_membase); | ||
1057 | if (hc->plx_membase) | ||
1058 | iounmap((void *)hc->plx_membase); | ||
1059 | if (hc->pci_iobase) | ||
1060 | release_region(hc->pci_iobase, 8); | ||
1061 | |||
1062 | if (hc->pci_dev) { | ||
1063 | pci_disable_device(hc->pci_dev); | ||
1064 | pci_set_drvdata(hc->pci_dev, NULL); | ||
1065 | } | ||
1066 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1067 | printk(KERN_DEBUG "%s: done\n", __func__); | ||
1068 | } | ||
1069 | |||
1070 | /* | ||
1071 | * function called to reset the HFC chip. A complete software reset of chip | ||
1072 | * and fifos is done. All configuration of the chip is done. | ||
1073 | */ | ||
1074 | |||
1075 | static int | ||
1076 | init_chip(struct hfc_multi *hc) | ||
1077 | { | ||
1078 | u_long flags, val, val2 = 0, rev; | ||
1079 | int i, err = 0; | ||
1080 | u_char r_conf_en, rval; | ||
1081 | u_int *plx_acc_32, pv; | ||
1082 | u_long plx_flags, hfc_flags; | ||
1083 | int plx_count; | ||
1084 | struct hfc_multi *pos, *next, *plx_last_hc; | ||
1085 | |||
1086 | spin_lock_irqsave(&hc->lock, flags); | ||
1087 | /* reset all registers */ | ||
1088 | memset(&hc->hw, 0, sizeof(struct hfcm_hw)); | ||
1089 | |||
1090 | /* revision check */ | ||
1091 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1092 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
1093 | val = HFC_inb(hc, R_CHIP_ID)>>4; | ||
1094 | if (val != 0x8 && val != 0xc && val != 0xe) { | ||
1095 | printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); | ||
1096 | err = -EIO; | ||
1097 | goto out; | ||
1098 | } | ||
1099 | rev = HFC_inb(hc, R_CHIP_RV); | ||
1100 | printk(KERN_INFO | ||
1101 | "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", | ||
1102 | val, rev, (rev == 0) ? " (old FIFO handling)" : ""); | ||
1103 | if (rev == 0) { | ||
1104 | test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); | ||
1105 | printk(KERN_WARNING | ||
1106 | "HFC_multi: NOTE: Your chip is revision 0, " | ||
1107 | "ask Cologne Chip for update. Newer chips " | ||
1108 | "have a better FIFO handling. Old chips " | ||
1109 | "still work but may have slightly lower " | ||
1110 | "HDLC transmit performance.\n"); | ||
1111 | } | ||
1112 | if (rev > 1) { | ||
1113 | printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't " | ||
1114 | "consider chip revision = %ld. The chip / " | ||
1115 | "bridge may not work.\n", rev); | ||
1116 | } | ||
1117 | |||
1118 | /* set s-ram size */ | ||
1119 | hc->Flen = 0x10; | ||
1120 | hc->Zmin = 0x80; | ||
1121 | hc->Zlen = 384; | ||
1122 | hc->DTMFbase = 0x1000; | ||
1123 | if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { | ||
1124 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1125 | printk(KERN_DEBUG "%s: changing to 128K extenal RAM\n", | ||
1126 | __func__); | ||
1127 | hc->hw.r_ctrl |= V_EXT_RAM; | ||
1128 | hc->hw.r_ram_sz = 1; | ||
1129 | hc->Flen = 0x20; | ||
1130 | hc->Zmin = 0xc0; | ||
1131 | hc->Zlen = 1856; | ||
1132 | hc->DTMFbase = 0x2000; | ||
1133 | } | ||
1134 | if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { | ||
1135 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1136 | printk(KERN_DEBUG "%s: changing to 512K extenal RAM\n", | ||
1137 | __func__); | ||
1138 | hc->hw.r_ctrl |= V_EXT_RAM; | ||
1139 | hc->hw.r_ram_sz = 2; | ||
1140 | hc->Flen = 0x20; | ||
1141 | hc->Zmin = 0xc0; | ||
1142 | hc->Zlen = 8000; | ||
1143 | hc->DTMFbase = 0x2000; | ||
1144 | } | ||
1145 | hc->max_trans = poll << 1; | ||
1146 | if (hc->max_trans > hc->Zlen) | ||
1147 | hc->max_trans = hc->Zlen; | ||
1148 | |||
1149 | /* Speech Design PLX bridge */ | ||
1150 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
1151 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
1152 | printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", | ||
1153 | __func__, hc->id + 1); | ||
1154 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
1155 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
1156 | writel(PLX_GPIOC_INIT, plx_acc_32); | ||
1157 | pv = readl(plx_acc_32); | ||
1158 | /* The first and the last cards are terminating the PCM bus */ | ||
1159 | pv |= PLX_TERM_ON; /* hc is currently the last */ | ||
1160 | /* Disconnect the PCM */ | ||
1161 | pv |= PLX_SLAVE_EN_N; | ||
1162 | pv &= ~PLX_MASTER_EN; | ||
1163 | pv &= ~PLX_SYNC_O_EN; | ||
1164 | /* Put the DSP in Reset */ | ||
1165 | pv &= ~PLX_DSP_RES_N; | ||
1166 | writel(pv, plx_acc_32); | ||
1167 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
1168 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1169 | printk(KERN_WARNING "%s: slave/term: PLX_GPIO=%x\n", | ||
1170 | __func__, pv); | ||
1171 | /* | ||
1172 | * If we are the 3rd PLXSD card or higher, we must turn | ||
1173 | * termination of last PLXSD card off. | ||
1174 | */ | ||
1175 | spin_lock_irqsave(&HFClock, hfc_flags); | ||
1176 | plx_count = 0; | ||
1177 | plx_last_hc = NULL; | ||
1178 | list_for_each_entry_safe(pos, next, &HFClist, list) { | ||
1179 | if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) { | ||
1180 | plx_count++; | ||
1181 | if (pos != hc) | ||
1182 | plx_last_hc = pos; | ||
1183 | } | ||
1184 | } | ||
1185 | if (plx_count >= 3) { | ||
1186 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
1187 | printk(KERN_DEBUG "%s: card %d is between, so " | ||
1188 | "we disable termination\n", | ||
1189 | __func__, plx_last_hc->id + 1); | ||
1190 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
1191 | plx_acc_32 = (u_int *)(plx_last_hc->plx_membase | ||
1192 | + PLX_GPIOC); | ||
1193 | pv = readl(plx_acc_32); | ||
1194 | pv &= ~PLX_TERM_ON; | ||
1195 | writel(pv, plx_acc_32); | ||
1196 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
1197 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1198 | printk(KERN_WARNING "%s: term off: PLX_GPIO=%x\n", | ||
1199 | __func__, pv); | ||
1200 | } | ||
1201 | spin_unlock_irqrestore(&HFClock, hfc_flags); | ||
1202 | hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ | ||
1203 | } | ||
1204 | |||
1205 | /* we only want the real Z2 read-pointer for revision > 0 */ | ||
1206 | if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) | ||
1207 | hc->hw.r_ram_sz |= V_FZ_MD; | ||
1208 | |||
1209 | /* select pcm mode */ | ||
1210 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
1211 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1212 | printk(KERN_DEBUG "%s: setting PCM into slave mode\n", | ||
1213 | __func__); | ||
1214 | } else | ||
1215 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) { | ||
1216 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1217 | printk(KERN_DEBUG "%s: setting PCM into master mode\n", | ||
1218 | __func__); | ||
1219 | hc->hw.r_pcm_md0 |= V_PCM_MD; | ||
1220 | } else { | ||
1221 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1222 | printk(KERN_DEBUG "%s: performing PCM auto detect\n", | ||
1223 | __func__); | ||
1224 | } | ||
1225 | |||
1226 | /* soft reset */ | ||
1227 | HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); | ||
1228 | HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); | ||
1229 | HFC_outb(hc, R_FIFO_MD, 0); | ||
1230 | hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR; | ||
1231 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
1232 | udelay(100); | ||
1233 | hc->hw.r_cirm = 0; | ||
1234 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
1235 | udelay(100); | ||
1236 | HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); | ||
1237 | |||
1238 | /* Speech Design PLX bridge pcm and sync mode */ | ||
1239 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
1240 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
1241 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
1242 | pv = readl(plx_acc_32); | ||
1243 | /* Connect PCM */ | ||
1244 | if (hc->hw.r_pcm_md0 & V_PCM_MD) { | ||
1245 | pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; | ||
1246 | pv |= PLX_SYNC_O_EN; | ||
1247 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1248 | printk(KERN_WARNING "%s: master: PLX_GPIO=%x\n", | ||
1249 | __func__, pv); | ||
1250 | } else { | ||
1251 | pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); | ||
1252 | pv &= ~PLX_SYNC_O_EN; | ||
1253 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1254 | printk(KERN_WARNING "%s: slave: PLX_GPIO=%x\n", | ||
1255 | __func__, pv); | ||
1256 | } | ||
1257 | writel(pv, plx_acc_32); | ||
1258 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
1259 | } | ||
1260 | |||
1261 | /* PCM setup */ | ||
1262 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); | ||
1263 | if (hc->slots == 32) | ||
1264 | HFC_outb(hc, R_PCM_MD1, 0x00); | ||
1265 | if (hc->slots == 64) | ||
1266 | HFC_outb(hc, R_PCM_MD1, 0x10); | ||
1267 | if (hc->slots == 128) | ||
1268 | HFC_outb(hc, R_PCM_MD1, 0x20); | ||
1269 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); | ||
1270 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | ||
1271 | HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ | ||
1272 | else | ||
1273 | HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ | ||
1274 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); | ||
1275 | for (i = 0; i < 256; i++) { | ||
1276 | HFC_outb_nodebug(hc, R_SLOT, i); | ||
1277 | HFC_outb_nodebug(hc, A_SL_CFG, 0); | ||
1278 | HFC_outb_nodebug(hc, A_CONF, 0); | ||
1279 | hc->slot_owner[i] = -1; | ||
1280 | } | ||
1281 | |||
1282 | /* set clock speed */ | ||
1283 | if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) { | ||
1284 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1285 | printk(KERN_DEBUG | ||
1286 | "%s: setting double clock\n", __func__); | ||
1287 | HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); | ||
1288 | } | ||
1289 | |||
1290 | /* B410P GPIO */ | ||
1291 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | ||
1292 | printk(KERN_NOTICE "Setting GPIOs\n"); | ||
1293 | HFC_outb(hc, R_GPIO_SEL, 0x30); | ||
1294 | HFC_outb(hc, R_GPIO_EN1, 0x3); | ||
1295 | udelay(1000); | ||
1296 | printk(KERN_NOTICE "calling vpm_init\n"); | ||
1297 | vpm_init(hc); | ||
1298 | } | ||
1299 | |||
1300 | /* check if R_F0_CNT counts (8 kHz frame count) */ | ||
1301 | val = HFC_inb(hc, R_F0_CNTL); | ||
1302 | val += HFC_inb(hc, R_F0_CNTH) << 8; | ||
1303 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1304 | printk(KERN_DEBUG | ||
1305 | "HFC_multi F0_CNT %ld after reset\n", val); | ||
1306 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1307 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1308 | schedule_timeout((HZ/100)?:1); /* Timeout minimum 10ms */ | ||
1309 | spin_lock_irqsave(&hc->lock, flags); | ||
1310 | val2 = HFC_inb(hc, R_F0_CNTL); | ||
1311 | val2 += HFC_inb(hc, R_F0_CNTH) << 8; | ||
1312 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1313 | printk(KERN_DEBUG | ||
1314 | "HFC_multi F0_CNT %ld after 10 ms (1st try)\n", | ||
1315 | val2); | ||
1316 | if (val2 >= val+8) { /* 1 ms */ | ||
1317 | /* it counts, so we keep the pcm mode */ | ||
1318 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) | ||
1319 | printk(KERN_INFO "controller is PCM bus MASTER\n"); | ||
1320 | else | ||
1321 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) | ||
1322 | printk(KERN_INFO "controller is PCM bus SLAVE\n"); | ||
1323 | else { | ||
1324 | test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
1325 | printk(KERN_INFO "controller is PCM bus SLAVE " | ||
1326 | "(auto detected)\n"); | ||
1327 | } | ||
1328 | } else { | ||
1329 | /* does not count */ | ||
1330 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { | ||
1331 | controller_fail: | ||
1332 | printk(KERN_ERR "HFC_multi ERROR, getting no 125us " | ||
1333 | "pulse. Seems that controller fails.\n"); | ||
1334 | err = -EIO; | ||
1335 | goto out; | ||
1336 | } | ||
1337 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
1338 | printk(KERN_INFO "controller is PCM bus SLAVE " | ||
1339 | "(ignoring missing PCM clock)\n"); | ||
1340 | } else { | ||
1341 | /* only one pcm master */ | ||
1342 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) | ||
1343 | && plxsd_master) { | ||
1344 | printk(KERN_ERR "HFC_multi ERROR, no clock " | ||
1345 | "on another Speech Design card found. " | ||
1346 | "Please be sure to connect PCM cable.\n"); | ||
1347 | err = -EIO; | ||
1348 | goto out; | ||
1349 | } | ||
1350 | /* retry with master clock */ | ||
1351 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
1352 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
1353 | plx_acc_32 = (u_int *)(hc->plx_membase + | ||
1354 | PLX_GPIOC); | ||
1355 | pv = readl(plx_acc_32); | ||
1356 | pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; | ||
1357 | pv |= PLX_SYNC_O_EN; | ||
1358 | writel(pv, plx_acc_32); | ||
1359 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
1360 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1361 | printk(KERN_WARNING "%s: master: PLX_GPIO" | ||
1362 | "=%x\n", __func__, pv); | ||
1363 | } | ||
1364 | hc->hw.r_pcm_md0 |= V_PCM_MD; | ||
1365 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); | ||
1366 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1367 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1368 | schedule_timeout((HZ/100)?:1); /* Timeout min. 10ms */ | ||
1369 | spin_lock_irqsave(&hc->lock, flags); | ||
1370 | val2 = HFC_inb(hc, R_F0_CNTL); | ||
1371 | val2 += HFC_inb(hc, R_F0_CNTH) << 8; | ||
1372 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1373 | printk(KERN_DEBUG "HFC_multi F0_CNT %ld after " | ||
1374 | "10 ms (2nd try)\n", val2); | ||
1375 | if (val2 >= val+8) { /* 1 ms */ | ||
1376 | test_and_set_bit(HFC_CHIP_PCM_MASTER, | ||
1377 | &hc->chip); | ||
1378 | printk(KERN_INFO "controller is PCM bus MASTER " | ||
1379 | "(auto detected)\n"); | ||
1380 | } else | ||
1381 | goto controller_fail; | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | /* Release the DSP Reset */ | ||
1386 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
1387 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) | ||
1388 | plxsd_master = 1; | ||
1389 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
1390 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
1391 | pv = readl(plx_acc_32); | ||
1392 | pv |= PLX_DSP_RES_N; | ||
1393 | writel(pv, plx_acc_32); | ||
1394 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
1395 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1396 | printk(KERN_WARNING "%s: reset off: PLX_GPIO=%x\n", | ||
1397 | __func__, pv); | ||
1398 | } | ||
1399 | |||
1400 | /* pcm id */ | ||
1401 | if (hc->pcm) | ||
1402 | printk(KERN_INFO "controller has given PCM BUS ID %d\n", | ||
1403 | hc->pcm); | ||
1404 | else { | ||
1405 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) | ||
1406 | || test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
1407 | PCM_cnt++; /* SD has proprietary bridging */ | ||
1408 | } | ||
1409 | hc->pcm = PCM_cnt; | ||
1410 | printk(KERN_INFO "controller has PCM BUS ID %d " | ||
1411 | "(auto selected)\n", hc->pcm); | ||
1412 | } | ||
1413 | |||
1414 | /* set up timer */ | ||
1415 | HFC_outb(hc, R_TI_WD, poll_timer); | ||
1416 | hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; | ||
1417 | |||
1418 | /* | ||
1419 | * set up 125us interrupt, only if function pointer is available | ||
1420 | * and module parameter timer is set | ||
1421 | */ | ||
1422 | if (timer && hfc_interrupt && register_interrupt) { | ||
1423 | /* only one chip should use this interrupt */ | ||
1424 | timer = 0; | ||
1425 | interrupt_registered = 1; | ||
1426 | hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK; | ||
1427 | /* deactivate other interrupts in ztdummy */ | ||
1428 | register_interrupt(); | ||
1429 | } | ||
1430 | |||
1431 | /* set E1 state machine IRQ */ | ||
1432 | if (hc->type == 1) | ||
1433 | hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; | ||
1434 | |||
1435 | /* set DTMF detection */ | ||
1436 | if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { | ||
1437 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1438 | printk(KERN_DEBUG "%s: enabling DTMF detection " | ||
1439 | "for all B-channel\n", __func__); | ||
1440 | hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; | ||
1441 | if (test_bit(HFC_CHIP_ULAW, &hc->chip)) | ||
1442 | hc->hw.r_dtmf |= V_ULAW_SEL; | ||
1443 | HFC_outb(hc, R_DTMF_N, 102 - 1); | ||
1444 | hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK; | ||
1445 | } | ||
1446 | |||
1447 | /* conference engine */ | ||
1448 | if (test_bit(HFC_CHIP_ULAW, &hc->chip)) | ||
1449 | r_conf_en = V_CONF_EN | V_ULAW; | ||
1450 | else | ||
1451 | r_conf_en = V_CONF_EN; | ||
1452 | HFC_outb(hc, R_CONF_EN, r_conf_en); | ||
1453 | |||
1454 | /* setting leds */ | ||
1455 | switch (hc->leds) { | ||
1456 | case 1: /* HFC-E1 OEM */ | ||
1457 | if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) | ||
1458 | HFC_outb(hc, R_GPIO_SEL, 0x32); | ||
1459 | else | ||
1460 | HFC_outb(hc, R_GPIO_SEL, 0x30); | ||
1461 | |||
1462 | HFC_outb(hc, R_GPIO_EN1, 0x0f); | ||
1463 | HFC_outb(hc, R_GPIO_OUT1, 0x00); | ||
1464 | |||
1465 | HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); | ||
1466 | break; | ||
1467 | |||
1468 | case 2: /* HFC-4S OEM */ | ||
1469 | case 3: | ||
1470 | HFC_outb(hc, R_GPIO_SEL, 0xf0); | ||
1471 | HFC_outb(hc, R_GPIO_EN1, 0xff); | ||
1472 | HFC_outb(hc, R_GPIO_OUT1, 0x00); | ||
1473 | break; | ||
1474 | } | ||
1475 | |||
1476 | /* set master clock */ | ||
1477 | if (hc->masterclk >= 0) { | ||
1478 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1479 | printk(KERN_DEBUG "%s: setting ST master clock " | ||
1480 | "to port %d (0..%d)\n", | ||
1481 | __func__, hc->masterclk, hc->ports-1); | ||
1482 | hc->hw.r_st_sync = hc->masterclk | V_AUTO_SYNC; | ||
1483 | HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); | ||
1484 | } | ||
1485 | |||
1486 | /* setting misc irq */ | ||
1487 | HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); | ||
1488 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1489 | printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", | ||
1490 | hc->hw.r_irqmsk_misc); | ||
1491 | |||
1492 | /* RAM access test */ | ||
1493 | HFC_outb(hc, R_RAM_ADDR0, 0); | ||
1494 | HFC_outb(hc, R_RAM_ADDR1, 0); | ||
1495 | HFC_outb(hc, R_RAM_ADDR2, 0); | ||
1496 | for (i = 0; i < 256; i++) { | ||
1497 | HFC_outb_nodebug(hc, R_RAM_ADDR0, i); | ||
1498 | HFC_outb_nodebug(hc, R_RAM_DATA, ((i*3)&0xff)); | ||
1499 | } | ||
1500 | for (i = 0; i < 256; i++) { | ||
1501 | HFC_outb_nodebug(hc, R_RAM_ADDR0, i); | ||
1502 | HFC_inb_nodebug(hc, R_RAM_DATA); | ||
1503 | rval = HFC_inb_nodebug(hc, R_INT_DATA); | ||
1504 | if (rval != ((i * 3) & 0xff)) { | ||
1505 | printk(KERN_DEBUG | ||
1506 | "addr:%x val:%x should:%x\n", i, rval, | ||
1507 | (i * 3) & 0xff); | ||
1508 | err++; | ||
1509 | } | ||
1510 | } | ||
1511 | if (err) { | ||
1512 | printk(KERN_DEBUG "aborting - %d RAM access errors\n", err); | ||
1513 | err = -EIO; | ||
1514 | goto out; | ||
1515 | } | ||
1516 | |||
1517 | if (debug & DEBUG_HFCMULTI_INIT) | ||
1518 | printk(KERN_DEBUG "%s: done\n", __func__); | ||
1519 | out: | ||
1520 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1521 | return err; | ||
1522 | } | ||
1523 | |||
1524 | |||
1525 | /* | ||
1526 | * control the watchdog | ||
1527 | */ | ||
1528 | static void | ||
1529 | hfcmulti_watchdog(struct hfc_multi *hc) | ||
1530 | { | ||
1531 | hc->wdcount++; | ||
1532 | |||
1533 | if (hc->wdcount > 10) { | ||
1534 | hc->wdcount = 0; | ||
1535 | hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ? | ||
1536 | V_GPIO_OUT3 : V_GPIO_OUT2; | ||
1537 | |||
1538 | /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */ | ||
1539 | HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); | ||
1540 | HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte); | ||
1541 | } | ||
1542 | } | ||
1543 | |||
1544 | |||
1545 | |||
1546 | /* | ||
1547 | * output leds | ||
1548 | */ | ||
1549 | static void | ||
1550 | hfcmulti_leds(struct hfc_multi *hc) | ||
1551 | { | ||
1552 | unsigned long lled; | ||
1553 | unsigned long leddw; | ||
1554 | int i, state, active, leds; | ||
1555 | struct dchannel *dch; | ||
1556 | int led[4]; | ||
1557 | |||
1558 | hc->ledcount += poll; | ||
1559 | if (hc->ledcount > 4096) { | ||
1560 | hc->ledcount -= 4096; | ||
1561 | hc->ledstate = 0xAFFEAFFE; | ||
1562 | } | ||
1563 | |||
1564 | switch (hc->leds) { | ||
1565 | case 1: /* HFC-E1 OEM */ | ||
1566 | /* 2 red blinking: NT mode deactivate | ||
1567 | * 2 red steady: TE mode deactivate | ||
1568 | * left green: L1 active | ||
1569 | * left red: frame sync, but no L1 | ||
1570 | * right green: L2 active | ||
1571 | */ | ||
1572 | if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */ | ||
1573 | if (hc->chan[hc->dslot].dch->dev.D.protocol | ||
1574 | != ISDN_P_NT_E1) { | ||
1575 | led[0] = 1; | ||
1576 | led[1] = 1; | ||
1577 | } else if (hc->ledcount>>11) { | ||
1578 | led[0] = 1; | ||
1579 | led[1] = 1; | ||
1580 | } else { | ||
1581 | led[0] = 0; | ||
1582 | led[1] = 0; | ||
1583 | } | ||
1584 | led[2] = 0; | ||
1585 | led[3] = 0; | ||
1586 | } else { /* with frame sync */ | ||
1587 | /* TODO make it work */ | ||
1588 | led[0] = 0; | ||
1589 | led[1] = 0; | ||
1590 | led[2] = 0; | ||
1591 | led[3] = 1; | ||
1592 | } | ||
1593 | leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; | ||
1594 | /* leds are inverted */ | ||
1595 | if (leds != (int)hc->ledstate) { | ||
1596 | HFC_outb_nodebug(hc, R_GPIO_OUT1, leds); | ||
1597 | hc->ledstate = leds; | ||
1598 | } | ||
1599 | break; | ||
1600 | |||
1601 | case 2: /* HFC-4S OEM */ | ||
1602 | /* red blinking = PH_DEACTIVATE NT Mode | ||
1603 | * red steady = PH_DEACTIVATE TE Mode | ||
1604 | * green steady = PH_ACTIVATE | ||
1605 | */ | ||
1606 | for (i = 0; i < 4; i++) { | ||
1607 | state = 0; | ||
1608 | active = -1; | ||
1609 | dch = hc->chan[(i << 2) | 2].dch; | ||
1610 | if (dch) { | ||
1611 | state = dch->state; | ||
1612 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
1613 | active = 3; | ||
1614 | else | ||
1615 | active = 7; | ||
1616 | } | ||
1617 | if (state) { | ||
1618 | if (state == active) { | ||
1619 | led[i] = 1; /* led green */ | ||
1620 | } else | ||
1621 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | ||
1622 | /* TE mode: led red */ | ||
1623 | led[i] = 2; | ||
1624 | else | ||
1625 | if (hc->ledcount>>11) | ||
1626 | /* led red */ | ||
1627 | led[i] = 2; | ||
1628 | else | ||
1629 | /* led off */ | ||
1630 | led[i] = 0; | ||
1631 | } else | ||
1632 | led[i] = 0; /* led off */ | ||
1633 | } | ||
1634 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | ||
1635 | leds = 0; | ||
1636 | for (i = 0; i < 4; i++) { | ||
1637 | if (led[i] == 1) { | ||
1638 | /*green*/ | ||
1639 | leds |= (0x2 << (i * 2)); | ||
1640 | } else if (led[i] == 2) { | ||
1641 | /*red*/ | ||
1642 | leds |= (0x1 << (i * 2)); | ||
1643 | } | ||
1644 | } | ||
1645 | if (leds != (int)hc->ledstate) { | ||
1646 | vpm_out(hc, 0, 0x1a8 + 3, leds); | ||
1647 | hc->ledstate = leds; | ||
1648 | } | ||
1649 | } else { | ||
1650 | leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) | | ||
1651 | ((led[0] > 0) << 2) | ((led[2] > 0) << 3) | | ||
1652 | ((led[3] & 1) << 4) | ((led[1] & 1) << 5) | | ||
1653 | ((led[0] & 1) << 6) | ((led[2] & 1) << 7); | ||
1654 | if (leds != (int)hc->ledstate) { | ||
1655 | HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F); | ||
1656 | HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4); | ||
1657 | hc->ledstate = leds; | ||
1658 | } | ||
1659 | } | ||
1660 | break; | ||
1661 | |||
1662 | case 3: /* HFC 1S/2S Beronet */ | ||
1663 | /* red blinking = PH_DEACTIVATE NT Mode | ||
1664 | * red steady = PH_DEACTIVATE TE Mode | ||
1665 | * green steady = PH_ACTIVATE | ||
1666 | */ | ||
1667 | for (i = 0; i < 2; i++) { | ||
1668 | state = 0; | ||
1669 | active = -1; | ||
1670 | dch = hc->chan[(i << 2) | 2].dch; | ||
1671 | if (dch) { | ||
1672 | state = dch->state; | ||
1673 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
1674 | active = 3; | ||
1675 | else | ||
1676 | active = 7; | ||
1677 | } | ||
1678 | if (state) { | ||
1679 | if (state == active) { | ||
1680 | led[i] = 1; /* led green */ | ||
1681 | } else | ||
1682 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | ||
1683 | /* TE mode: led red */ | ||
1684 | led[i] = 2; | ||
1685 | else | ||
1686 | if (hc->ledcount >> 11) | ||
1687 | /* led red */ | ||
1688 | led[i] = 2; | ||
1689 | else | ||
1690 | /* led off */ | ||
1691 | led[i] = 0; | ||
1692 | } else | ||
1693 | led[i] = 0; /* led off */ | ||
1694 | } | ||
1695 | |||
1696 | |||
1697 | leds = (led[0] > 0) | ((led[1] > 0)<<1) | ((led[0]&1)<<2) | ||
1698 | | ((led[1]&1)<<3); | ||
1699 | if (leds != (int)hc->ledstate) { | ||
1700 | HFC_outb_nodebug(hc, R_GPIO_EN1, | ||
1701 | ((led[0] > 0) << 2) | ((led[1] > 0) << 3)); | ||
1702 | HFC_outb_nodebug(hc, R_GPIO_OUT1, | ||
1703 | ((led[0] & 1) << 2) | ((led[1] & 1) << 3)); | ||
1704 | hc->ledstate = leds; | ||
1705 | } | ||
1706 | break; | ||
1707 | case 8: /* HFC 8S+ Beronet */ | ||
1708 | lled = 0; | ||
1709 | |||
1710 | for (i = 0; i < 8; i++) { | ||
1711 | state = 0; | ||
1712 | active = -1; | ||
1713 | dch = hc->chan[(i << 2) | 2].dch; | ||
1714 | if (dch) { | ||
1715 | state = dch->state; | ||
1716 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
1717 | active = 3; | ||
1718 | else | ||
1719 | active = 7; | ||
1720 | } | ||
1721 | if (state) { | ||
1722 | if (state == active) { | ||
1723 | lled |= 0 << i; | ||
1724 | } else | ||
1725 | if (hc->ledcount >> 11) | ||
1726 | lled |= 0 << i; | ||
1727 | else | ||
1728 | lled |= 1 << i; | ||
1729 | } else | ||
1730 | lled |= 1 << i; | ||
1731 | } | ||
1732 | leddw = lled << 24 | lled << 16 | lled << 8 | lled; | ||
1733 | if (leddw != hc->ledstate) { | ||
1734 | /* HFC_outb(hc, R_BRG_PCM_CFG, 1); | ||
1735 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */ | ||
1736 | /* was _io before */ | ||
1737 | HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); | ||
1738 | outw(0x4000, hc->pci_iobase + 4); | ||
1739 | outl(leddw, hc->pci_iobase); | ||
1740 | HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK); | ||
1741 | hc->ledstate = leddw; | ||
1742 | } | ||
1743 | break; | ||
1744 | } | ||
1745 | } | ||
1746 | /* | ||
1747 | * read dtmf coefficients | ||
1748 | */ | ||
1749 | |||
1750 | static void | ||
1751 | hfcmulti_dtmf(struct hfc_multi *hc) | ||
1752 | { | ||
1753 | s32 *coeff; | ||
1754 | u_int mantissa; | ||
1755 | int co, ch; | ||
1756 | struct bchannel *bch = NULL; | ||
1757 | u8 exponent; | ||
1758 | int dtmf = 0; | ||
1759 | int addr; | ||
1760 | u16 w_float; | ||
1761 | struct sk_buff *skb; | ||
1762 | struct mISDNhead *hh; | ||
1763 | |||
1764 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
1765 | printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__); | ||
1766 | for (ch = 0; ch <= 31; ch++) { | ||
1767 | /* only process enabled B-channels */ | ||
1768 | bch = hc->chan[ch].bch; | ||
1769 | if (!bch) | ||
1770 | continue; | ||
1771 | if (!hc->created[hc->chan[ch].port]) | ||
1772 | continue; | ||
1773 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
1774 | continue; | ||
1775 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
1776 | printk(KERN_DEBUG "%s: dtmf channel %d:", | ||
1777 | __func__, ch); | ||
1778 | coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]); | ||
1779 | dtmf = 1; | ||
1780 | for (co = 0; co < 8; co++) { | ||
1781 | /* read W(n-1) coefficient */ | ||
1782 | addr = hc->DTMFbase + ((co<<7) | (ch<<2)); | ||
1783 | HFC_outb_nodebug(hc, R_RAM_ADDR0, addr); | ||
1784 | HFC_outb_nodebug(hc, R_RAM_ADDR1, addr>>8); | ||
1785 | HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr>>16) | ||
1786 | | V_ADDR_INC); | ||
1787 | w_float = HFC_inb_nodebug(hc, R_RAM_DATA); | ||
1788 | w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); | ||
1789 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
1790 | printk(" %04x", w_float); | ||
1791 | |||
1792 | /* decode float (see chip doc) */ | ||
1793 | mantissa = w_float & 0x0fff; | ||
1794 | if (w_float & 0x8000) | ||
1795 | mantissa |= 0xfffff000; | ||
1796 | exponent = (w_float>>12) & 0x7; | ||
1797 | if (exponent) { | ||
1798 | mantissa ^= 0x1000; | ||
1799 | mantissa <<= (exponent-1); | ||
1800 | } | ||
1801 | |||
1802 | /* store coefficient */ | ||
1803 | coeff[co<<1] = mantissa; | ||
1804 | |||
1805 | /* read W(n) coefficient */ | ||
1806 | w_float = HFC_inb_nodebug(hc, R_RAM_DATA); | ||
1807 | w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); | ||
1808 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
1809 | printk(" %04x", w_float); | ||
1810 | |||
1811 | /* decode float (see chip doc) */ | ||
1812 | mantissa = w_float & 0x0fff; | ||
1813 | if (w_float & 0x8000) | ||
1814 | mantissa |= 0xfffff000; | ||
1815 | exponent = (w_float>>12) & 0x7; | ||
1816 | if (exponent) { | ||
1817 | mantissa ^= 0x1000; | ||
1818 | mantissa <<= (exponent-1); | ||
1819 | } | ||
1820 | |||
1821 | /* store coefficient */ | ||
1822 | coeff[(co<<1)|1] = mantissa; | ||
1823 | } | ||
1824 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
1825 | printk("%s: DTMF ready %08x %08x %08x %08x " | ||
1826 | "%08x %08x %08x %08x\n", __func__, | ||
1827 | coeff[0], coeff[1], coeff[2], coeff[3], | ||
1828 | coeff[4], coeff[5], coeff[6], coeff[7]); | ||
1829 | hc->chan[ch].coeff_count++; | ||
1830 | if (hc->chan[ch].coeff_count == 8) { | ||
1831 | hc->chan[ch].coeff_count = 0; | ||
1832 | skb = mI_alloc_skb(512, GFP_ATOMIC); | ||
1833 | if (!skb) { | ||
1834 | printk(KERN_WARNING "%s: No memory for skb\n", | ||
1835 | __func__); | ||
1836 | continue; | ||
1837 | } | ||
1838 | hh = mISDN_HEAD_P(skb); | ||
1839 | hh->prim = PH_CONTROL_IND; | ||
1840 | hh->id = DTMF_HFC_COEF; | ||
1841 | memcpy(skb_put(skb, 512), hc->chan[ch].coeff, 512); | ||
1842 | recv_Bchannel_skb(bch, skb); | ||
1843 | } | ||
1844 | } | ||
1845 | |||
1846 | /* restart DTMF processing */ | ||
1847 | hc->dtmf = dtmf; | ||
1848 | if (dtmf) | ||
1849 | HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); | ||
1850 | } | ||
1851 | |||
1852 | |||
1853 | /* | ||
1854 | * fill fifo as much as possible | ||
1855 | */ | ||
1856 | |||
1857 | static void | ||
1858 | hfcmulti_tx(struct hfc_multi *hc, int ch) | ||
1859 | { | ||
1860 | int i, ii, temp, len = 0; | ||
1861 | int Zspace, z1, z2; /* must be int for calculation */ | ||
1862 | int Fspace, f1, f2; | ||
1863 | u_char *d; | ||
1864 | int *txpending, slot_tx; | ||
1865 | struct bchannel *bch; | ||
1866 | struct dchannel *dch; | ||
1867 | struct sk_buff **sp = NULL; | ||
1868 | int *idxp; | ||
1869 | |||
1870 | bch = hc->chan[ch].bch; | ||
1871 | dch = hc->chan[ch].dch; | ||
1872 | if ((!dch) && (!bch)) | ||
1873 | return; | ||
1874 | |||
1875 | txpending = &hc->chan[ch].txpending; | ||
1876 | slot_tx = hc->chan[ch].slot_tx; | ||
1877 | if (dch) { | ||
1878 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | ||
1879 | return; | ||
1880 | sp = &dch->tx_skb; | ||
1881 | idxp = &dch->tx_idx; | ||
1882 | } else { | ||
1883 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | ||
1884 | return; | ||
1885 | sp = &bch->tx_skb; | ||
1886 | idxp = &bch->tx_idx; | ||
1887 | } | ||
1888 | if (*sp) | ||
1889 | len = (*sp)->len; | ||
1890 | |||
1891 | if ((!len) && *txpending != 1) | ||
1892 | return; /* no data */ | ||
1893 | |||
1894 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | ||
1895 | (hc->chan[ch].protocol == ISDN_P_B_RAW) && | ||
1896 | (hc->chan[ch].slot_rx < 0) && | ||
1897 | (hc->chan[ch].slot_tx < 0)) | ||
1898 | HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1)); | ||
1899 | else | ||
1900 | HFC_outb_nodebug(hc, R_FIFO, ch << 1); | ||
1901 | HFC_wait_nodebug(hc); | ||
1902 | |||
1903 | if (*txpending == 2) { | ||
1904 | /* reset fifo */ | ||
1905 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | ||
1906 | HFC_wait_nodebug(hc); | ||
1907 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
1908 | *txpending = 1; | ||
1909 | } | ||
1910 | next_frame: | ||
1911 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
1912 | f1 = HFC_inb_nodebug(hc, A_F1); | ||
1913 | f2 = HFC_inb_nodebug(hc, A_F2); | ||
1914 | while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) { | ||
1915 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
1916 | printk(KERN_DEBUG | ||
1917 | "%s(card %d): reread f2 because %d!=%d\n", | ||
1918 | __func__, hc->id + 1, temp, f2); | ||
1919 | f2 = temp; /* repeat until F2 is equal */ | ||
1920 | } | ||
1921 | Fspace = f2 - f1 - 1; | ||
1922 | if (Fspace < 0) | ||
1923 | Fspace += hc->Flen; | ||
1924 | /* | ||
1925 | * Old FIFO handling doesn't give us the current Z2 read | ||
1926 | * pointer, so we cannot send the next frame before the fifo | ||
1927 | * is empty. It makes no difference except for a slightly | ||
1928 | * lower performance. | ||
1929 | */ | ||
1930 | if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) { | ||
1931 | if (f1 != f2) | ||
1932 | Fspace = 0; | ||
1933 | else | ||
1934 | Fspace = 1; | ||
1935 | } | ||
1936 | /* one frame only for ST D-channels, to allow resending */ | ||
1937 | if (hc->type != 1 && dch) { | ||
1938 | if (f1 != f2) | ||
1939 | Fspace = 0; | ||
1940 | } | ||
1941 | /* F-counter full condition */ | ||
1942 | if (Fspace == 0) | ||
1943 | return; | ||
1944 | } | ||
1945 | z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; | ||
1946 | z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; | ||
1947 | while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) { | ||
1948 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
1949 | printk(KERN_DEBUG "%s(card %d): reread z2 because " | ||
1950 | "%d!=%d\n", __func__, hc->id + 1, temp, z2); | ||
1951 | z2 = temp; /* repeat unti Z2 is equal */ | ||
1952 | } | ||
1953 | Zspace = z2 - z1; | ||
1954 | if (Zspace <= 0) | ||
1955 | Zspace += hc->Zlen; | ||
1956 | Zspace -= 4; /* keep not too full, so pointers will not overrun */ | ||
1957 | /* fill transparent data only to maxinum transparent load (minus 4) */ | ||
1958 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
1959 | Zspace = Zspace - hc->Zlen + hc->max_trans; | ||
1960 | if (Zspace <= 0) /* no space of 4 bytes */ | ||
1961 | return; | ||
1962 | |||
1963 | /* if no data */ | ||
1964 | if (!len) { | ||
1965 | if (z1 == z2) { /* empty */ | ||
1966 | /* if done with FIFO audio data during PCM connection */ | ||
1967 | if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && | ||
1968 | *txpending && slot_tx >= 0) { | ||
1969 | if (debug & DEBUG_HFCMULTI_MODE) | ||
1970 | printk(KERN_DEBUG | ||
1971 | "%s: reconnecting PCM due to no " | ||
1972 | "more FIFO data: channel %d " | ||
1973 | "slot_tx %d\n", | ||
1974 | __func__, ch, slot_tx); | ||
1975 | /* connect slot */ | ||
1976 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | | ||
1977 | V_HDLC_TRP | V_IFF); | ||
1978 | HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); | ||
1979 | HFC_wait_nodebug(hc); | ||
1980 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | | ||
1981 | V_HDLC_TRP | V_IFF); | ||
1982 | HFC_outb_nodebug(hc, R_FIFO, ch<<1); | ||
1983 | HFC_wait_nodebug(hc); | ||
1984 | } | ||
1985 | *txpending = 0; | ||
1986 | } | ||
1987 | return; /* no data */ | ||
1988 | } | ||
1989 | |||
1990 | /* if audio data and connected slot */ | ||
1991 | if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) | ||
1992 | && slot_tx >= 0) { | ||
1993 | if (debug & DEBUG_HFCMULTI_MODE) | ||
1994 | printk(KERN_DEBUG "%s: disconnecting PCM due to " | ||
1995 | "FIFO data: channel %d slot_tx %d\n", | ||
1996 | __func__, ch, slot_tx); | ||
1997 | /* disconnect slot */ | ||
1998 | HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); | ||
1999 | HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); | ||
2000 | HFC_wait_nodebug(hc); | ||
2001 | HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); | ||
2002 | HFC_outb_nodebug(hc, R_FIFO, ch<<1); | ||
2003 | HFC_wait_nodebug(hc); | ||
2004 | } | ||
2005 | *txpending = 1; | ||
2006 | |||
2007 | /* show activity */ | ||
2008 | hc->activity[hc->chan[ch].port] = 1; | ||
2009 | |||
2010 | /* fill fifo to what we have left */ | ||
2011 | ii = len; | ||
2012 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) | ||
2013 | temp = 1; | ||
2014 | else | ||
2015 | temp = 0; | ||
2016 | i = *idxp; | ||
2017 | d = (*sp)->data + i; | ||
2018 | if (ii - i > Zspace) | ||
2019 | ii = Zspace + i; | ||
2020 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2021 | printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " | ||
2022 | "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", | ||
2023 | __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, | ||
2024 | temp ? "HDLC":"TRANS"); | ||
2025 | |||
2026 | |||
2027 | /* Have to prep the audio data */ | ||
2028 | hc->write_fifo(hc, d, ii - i); | ||
2029 | *idxp = ii; | ||
2030 | |||
2031 | /* if not all data has been written */ | ||
2032 | if (ii != len) { | ||
2033 | /* NOTE: fifo is started by the calling function */ | ||
2034 | return; | ||
2035 | } | ||
2036 | |||
2037 | /* if all data has been written, terminate frame */ | ||
2038 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
2039 | /* increment f-counter */ | ||
2040 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); | ||
2041 | HFC_wait_nodebug(hc); | ||
2042 | } | ||
2043 | |||
2044 | /* send confirm, since get_net_bframe will not do it with trans */ | ||
2045 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
2046 | confirm_Bsend(bch); | ||
2047 | |||
2048 | /* check for next frame */ | ||
2049 | dev_kfree_skb(*sp); | ||
2050 | if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */ | ||
2051 | len = (*sp)->len; | ||
2052 | goto next_frame; | ||
2053 | } | ||
2054 | if (dch && get_next_dframe(dch)) { | ||
2055 | len = (*sp)->len; | ||
2056 | goto next_frame; | ||
2057 | } | ||
2058 | |||
2059 | /* | ||
2060 | * now we have no more data, so in case of transparent, | ||
2061 | * we set the last byte in fifo to 'silence' in case we will get | ||
2062 | * no more data at all. this prevents sending an undefined value. | ||
2063 | */ | ||
2064 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
2065 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); | ||
2066 | } | ||
2067 | |||
2068 | |||
2069 | /* NOTE: only called if E1 card is in active state */ | ||
2070 | static void | ||
2071 | hfcmulti_rx(struct hfc_multi *hc, int ch) | ||
2072 | { | ||
2073 | int temp; | ||
2074 | int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ | ||
2075 | int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ | ||
2076 | int again = 0; | ||
2077 | struct bchannel *bch; | ||
2078 | struct dchannel *dch; | ||
2079 | struct sk_buff *skb, **sp = NULL; | ||
2080 | int maxlen; | ||
2081 | |||
2082 | bch = hc->chan[ch].bch; | ||
2083 | dch = hc->chan[ch].dch; | ||
2084 | if ((!dch) && (!bch)) | ||
2085 | return; | ||
2086 | if (dch) { | ||
2087 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | ||
2088 | return; | ||
2089 | sp = &dch->rx_skb; | ||
2090 | maxlen = dch->maxlen; | ||
2091 | } else { | ||
2092 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | ||
2093 | return; | ||
2094 | sp = &bch->rx_skb; | ||
2095 | maxlen = bch->maxlen; | ||
2096 | } | ||
2097 | next_frame: | ||
2098 | /* on first AND before getting next valid frame, R_FIFO must be written | ||
2099 | to. */ | ||
2100 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | ||
2101 | (hc->chan[ch].protocol == ISDN_P_B_RAW) && | ||
2102 | (hc->chan[ch].slot_rx < 0) && | ||
2103 | (hc->chan[ch].slot_tx < 0)) | ||
2104 | HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch<<1) | 1); | ||
2105 | else | ||
2106 | HFC_outb_nodebug(hc, R_FIFO, (ch<<1)|1); | ||
2107 | HFC_wait_nodebug(hc); | ||
2108 | |||
2109 | /* ignore if rx is off BUT change fifo (above) to start pending TX */ | ||
2110 | if (hc->chan[ch].rx_off) | ||
2111 | return; | ||
2112 | |||
2113 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
2114 | f1 = HFC_inb_nodebug(hc, A_F1); | ||
2115 | while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { | ||
2116 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2117 | printk(KERN_DEBUG | ||
2118 | "%s(card %d): reread f1 because %d!=%d\n", | ||
2119 | __func__, hc->id + 1, temp, f1); | ||
2120 | f1 = temp; /* repeat until F1 is equal */ | ||
2121 | } | ||
2122 | f2 = HFC_inb_nodebug(hc, A_F2); | ||
2123 | } | ||
2124 | z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; | ||
2125 | while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { | ||
2126 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2127 | printk(KERN_DEBUG "%s(card %d): reread z2 because " | ||
2128 | "%d!=%d\n", __func__, hc->id + 1, temp, z2); | ||
2129 | z1 = temp; /* repeat until Z1 is equal */ | ||
2130 | } | ||
2131 | z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; | ||
2132 | Zsize = z1 - z2; | ||
2133 | if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) | ||
2134 | /* complete hdlc frame */ | ||
2135 | Zsize++; | ||
2136 | if (Zsize < 0) | ||
2137 | Zsize += hc->Zlen; | ||
2138 | /* if buffer is empty */ | ||
2139 | if (Zsize <= 0) | ||
2140 | return; | ||
2141 | |||
2142 | if (*sp == NULL) { | ||
2143 | *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); | ||
2144 | if (*sp == NULL) { | ||
2145 | printk(KERN_DEBUG "%s: No mem for rx_skb\n", | ||
2146 | __func__); | ||
2147 | return; | ||
2148 | } | ||
2149 | } | ||
2150 | /* show activity */ | ||
2151 | hc->activity[hc->chan[ch].port] = 1; | ||
2152 | |||
2153 | /* empty fifo with what we have */ | ||
2154 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
2155 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2156 | printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " | ||
2157 | "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " | ||
2158 | "got=%d (again %d)\n", __func__, hc->id + 1, ch, | ||
2159 | Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", | ||
2160 | f1, f2, Zsize + (*sp)->len, again); | ||
2161 | /* HDLC */ | ||
2162 | if ((Zsize + (*sp)->len) > (maxlen + 3)) { | ||
2163 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2164 | printk(KERN_DEBUG | ||
2165 | "%s(card %d): hdlc-frame too large.\n", | ||
2166 | __func__, hc->id + 1); | ||
2167 | skb_trim(*sp, 0); | ||
2168 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | ||
2169 | HFC_wait_nodebug(hc); | ||
2170 | return; | ||
2171 | } | ||
2172 | |||
2173 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | ||
2174 | |||
2175 | if (f1 != f2) { | ||
2176 | /* increment Z2,F2-counter */ | ||
2177 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); | ||
2178 | HFC_wait_nodebug(hc); | ||
2179 | /* check size */ | ||
2180 | if ((*sp)->len < 4) { | ||
2181 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2182 | printk(KERN_DEBUG | ||
2183 | "%s(card %d): Frame below minimum " | ||
2184 | "size\n", __func__, hc->id + 1); | ||
2185 | skb_trim(*sp, 0); | ||
2186 | goto next_frame; | ||
2187 | } | ||
2188 | /* there is at least one complete frame, check crc */ | ||
2189 | if ((*sp)->data[(*sp)->len - 1]) { | ||
2190 | if (debug & DEBUG_HFCMULTI_CRC) | ||
2191 | printk(KERN_DEBUG | ||
2192 | "%s: CRC-error\n", __func__); | ||
2193 | skb_trim(*sp, 0); | ||
2194 | goto next_frame; | ||
2195 | } | ||
2196 | skb_trim(*sp, (*sp)->len - 3); | ||
2197 | if ((*sp)->len < MISDN_COPY_SIZE) { | ||
2198 | skb = *sp; | ||
2199 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | ||
2200 | if (*sp) { | ||
2201 | memcpy(skb_put(*sp, skb->len), | ||
2202 | skb->data, skb->len); | ||
2203 | skb_trim(skb, 0); | ||
2204 | } else { | ||
2205 | printk(KERN_DEBUG "%s: No mem\n", | ||
2206 | __func__); | ||
2207 | *sp = skb; | ||
2208 | skb = NULL; | ||
2209 | } | ||
2210 | } else { | ||
2211 | skb = NULL; | ||
2212 | } | ||
2213 | if (debug & DEBUG_HFCMULTI_FIFO) { | ||
2214 | printk(KERN_DEBUG "%s(card %d):", | ||
2215 | __func__, hc->id + 1); | ||
2216 | temp = 0; | ||
2217 | while (temp < (*sp)->len) | ||
2218 | printk(" %02x", (*sp)->data[temp++]); | ||
2219 | printk("\n"); | ||
2220 | } | ||
2221 | if (dch) | ||
2222 | recv_Dchannel(dch); | ||
2223 | else | ||
2224 | recv_Bchannel(bch); | ||
2225 | *sp = skb; | ||
2226 | again++; | ||
2227 | goto next_frame; | ||
2228 | } | ||
2229 | /* there is an incomplete frame */ | ||
2230 | } else { | ||
2231 | /* transparent */ | ||
2232 | if (Zsize > skb_tailroom(*sp)) | ||
2233 | Zsize = skb_tailroom(*sp); | ||
2234 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | ||
2235 | if (((*sp)->len) < MISDN_COPY_SIZE) { | ||
2236 | skb = *sp; | ||
2237 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | ||
2238 | if (*sp) { | ||
2239 | memcpy(skb_put(*sp, skb->len), | ||
2240 | skb->data, skb->len); | ||
2241 | skb_trim(skb, 0); | ||
2242 | } else { | ||
2243 | printk(KERN_DEBUG "%s: No mem\n", __func__); | ||
2244 | *sp = skb; | ||
2245 | skb = NULL; | ||
2246 | } | ||
2247 | } else { | ||
2248 | skb = NULL; | ||
2249 | } | ||
2250 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
2251 | printk(KERN_DEBUG | ||
2252 | "%s(card %d): fifo(%d) reading %d bytes " | ||
2253 | "(z1=%04x, z2=%04x) TRANS\n", | ||
2254 | __func__, hc->id + 1, ch, Zsize, z1, z2); | ||
2255 | /* only bch is transparent */ | ||
2256 | recv_Bchannel(bch); | ||
2257 | *sp = skb; | ||
2258 | } | ||
2259 | } | ||
2260 | |||
2261 | |||
2262 | /* | ||
2263 | * Interrupt handler | ||
2264 | */ | ||
2265 | static void | ||
2266 | signal_state_up(struct dchannel *dch, int info, char *msg) | ||
2267 | { | ||
2268 | struct sk_buff *skb; | ||
2269 | int id, data = info; | ||
2270 | |||
2271 | if (debug & DEBUG_HFCMULTI_STATE) | ||
2272 | printk(KERN_DEBUG "%s: %s\n", __func__, msg); | ||
2273 | |||
2274 | id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */ | ||
2275 | |||
2276 | skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data, | ||
2277 | GFP_ATOMIC); | ||
2278 | if (!skb) | ||
2279 | return; | ||
2280 | recv_Dchannel_skb(dch, skb); | ||
2281 | } | ||
2282 | |||
2283 | static inline void | ||
2284 | handle_timer_irq(struct hfc_multi *hc) | ||
2285 | { | ||
2286 | int ch, temp; | ||
2287 | struct dchannel *dch; | ||
2288 | u_long flags; | ||
2289 | |||
2290 | /* process queued resync jobs */ | ||
2291 | if (hc->e1_resync) { | ||
2292 | /* lock, so e1_resync gets not changed */ | ||
2293 | spin_lock_irqsave(&HFClock, flags); | ||
2294 | if (hc->e1_resync & 1) { | ||
2295 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
2296 | printk(KERN_DEBUG "Enable SYNC_I\n"); | ||
2297 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); | ||
2298 | /* disable JATT, if RX_SYNC is set */ | ||
2299 | if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) | ||
2300 | HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); | ||
2301 | } | ||
2302 | if (hc->e1_resync & 2) { | ||
2303 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
2304 | printk(KERN_DEBUG "Enable jatt PLL\n"); | ||
2305 | HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); | ||
2306 | } | ||
2307 | if (hc->e1_resync & 4) { | ||
2308 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
2309 | printk(KERN_DEBUG | ||
2310 | "Enable QUARTZ for HFC-E1\n"); | ||
2311 | /* set jatt to quartz */ | ||
2312 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | ||
2313 | | V_JATT_OFF); | ||
2314 | /* switch to JATT, in case it is not already */ | ||
2315 | HFC_outb(hc, R_SYNC_OUT, 0); | ||
2316 | } | ||
2317 | hc->e1_resync = 0; | ||
2318 | spin_unlock_irqrestore(&HFClock, flags); | ||
2319 | } | ||
2320 | |||
2321 | if (hc->type != 1 || hc->e1_state == 1) | ||
2322 | for (ch = 0; ch <= 31; ch++) { | ||
2323 | if (hc->created[hc->chan[ch].port]) { | ||
2324 | hfcmulti_tx(hc, ch); | ||
2325 | /* fifo is started when switching to rx-fifo */ | ||
2326 | hfcmulti_rx(hc, ch); | ||
2327 | if (hc->chan[ch].dch && | ||
2328 | hc->chan[ch].nt_timer > -1) { | ||
2329 | dch = hc->chan[ch].dch; | ||
2330 | if (!(--hc->chan[ch].nt_timer)) { | ||
2331 | schedule_event(dch, | ||
2332 | FLG_PHCHANGE); | ||
2333 | if (debug & | ||
2334 | DEBUG_HFCMULTI_STATE) | ||
2335 | printk(KERN_DEBUG | ||
2336 | "%s: nt_timer at " | ||
2337 | "state %x\n", | ||
2338 | __func__, | ||
2339 | dch->state); | ||
2340 | } | ||
2341 | } | ||
2342 | } | ||
2343 | } | ||
2344 | if (hc->type == 1 && hc->created[0]) { | ||
2345 | dch = hc->chan[hc->dslot].dch; | ||
2346 | if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { | ||
2347 | /* LOS */ | ||
2348 | temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; | ||
2349 | if (!temp && hc->chan[hc->dslot].los) | ||
2350 | signal_state_up(dch, L1_SIGNAL_LOS_ON, | ||
2351 | "LOS detected"); | ||
2352 | if (temp && !hc->chan[hc->dslot].los) | ||
2353 | signal_state_up(dch, L1_SIGNAL_LOS_OFF, | ||
2354 | "LOS gone"); | ||
2355 | hc->chan[hc->dslot].los = temp; | ||
2356 | } | ||
2357 | if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dslot].cfg)) { | ||
2358 | /* AIS */ | ||
2359 | temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; | ||
2360 | if (!temp && hc->chan[hc->dslot].ais) | ||
2361 | signal_state_up(dch, L1_SIGNAL_AIS_ON, | ||
2362 | "AIS detected"); | ||
2363 | if (temp && !hc->chan[hc->dslot].ais) | ||
2364 | signal_state_up(dch, L1_SIGNAL_AIS_OFF, | ||
2365 | "AIS gone"); | ||
2366 | hc->chan[hc->dslot].ais = temp; | ||
2367 | } | ||
2368 | if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dslot].cfg)) { | ||
2369 | /* SLIP */ | ||
2370 | temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; | ||
2371 | if (!temp && hc->chan[hc->dslot].slip_rx) | ||
2372 | signal_state_up(dch, L1_SIGNAL_SLIP_RX, | ||
2373 | " bit SLIP detected RX"); | ||
2374 | hc->chan[hc->dslot].slip_rx = temp; | ||
2375 | temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; | ||
2376 | if (!temp && hc->chan[hc->dslot].slip_tx) | ||
2377 | signal_state_up(dch, L1_SIGNAL_SLIP_TX, | ||
2378 | " bit SLIP detected TX"); | ||
2379 | hc->chan[hc->dslot].slip_tx = temp; | ||
2380 | } | ||
2381 | if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dslot].cfg)) { | ||
2382 | /* RDI */ | ||
2383 | temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; | ||
2384 | if (!temp && hc->chan[hc->dslot].rdi) | ||
2385 | signal_state_up(dch, L1_SIGNAL_RDI_ON, | ||
2386 | "RDI detected"); | ||
2387 | if (temp && !hc->chan[hc->dslot].rdi) | ||
2388 | signal_state_up(dch, L1_SIGNAL_RDI_OFF, | ||
2389 | "RDI gone"); | ||
2390 | hc->chan[hc->dslot].rdi = temp; | ||
2391 | } | ||
2392 | temp = HFC_inb_nodebug(hc, R_JATT_DIR); | ||
2393 | switch (hc->chan[hc->dslot].sync) { | ||
2394 | case 0: | ||
2395 | if ((temp & 0x60) == 0x60) { | ||
2396 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
2397 | printk(KERN_DEBUG | ||
2398 | "%s: (id=%d) E1 now " | ||
2399 | "in clock sync\n", | ||
2400 | __func__, hc->id); | ||
2401 | HFC_outb(hc, R_RX_OFF, | ||
2402 | hc->chan[hc->dslot].jitter | V_RX_INIT); | ||
2403 | HFC_outb(hc, R_TX_OFF, | ||
2404 | hc->chan[hc->dslot].jitter | V_RX_INIT); | ||
2405 | hc->chan[hc->dslot].sync = 1; | ||
2406 | goto check_framesync; | ||
2407 | } | ||
2408 | break; | ||
2409 | case 1: | ||
2410 | if ((temp & 0x60) != 0x60) { | ||
2411 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
2412 | printk(KERN_DEBUG | ||
2413 | "%s: (id=%d) E1 " | ||
2414 | "lost clock sync\n", | ||
2415 | __func__, hc->id); | ||
2416 | hc->chan[hc->dslot].sync = 0; | ||
2417 | break; | ||
2418 | } | ||
2419 | check_framesync: | ||
2420 | temp = HFC_inb_nodebug(hc, R_SYNC_STA); | ||
2421 | if (temp == 0x27) { | ||
2422 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
2423 | printk(KERN_DEBUG | ||
2424 | "%s: (id=%d) E1 " | ||
2425 | "now in frame sync\n", | ||
2426 | __func__, hc->id); | ||
2427 | hc->chan[hc->dslot].sync = 2; | ||
2428 | } | ||
2429 | break; | ||
2430 | case 2: | ||
2431 | if ((temp & 0x60) != 0x60) { | ||
2432 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
2433 | printk(KERN_DEBUG | ||
2434 | "%s: (id=%d) E1 lost " | ||
2435 | "clock & frame sync\n", | ||
2436 | __func__, hc->id); | ||
2437 | hc->chan[hc->dslot].sync = 0; | ||
2438 | break; | ||
2439 | } | ||
2440 | temp = HFC_inb_nodebug(hc, R_SYNC_STA); | ||
2441 | if (temp != 0x27) { | ||
2442 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
2443 | printk(KERN_DEBUG | ||
2444 | "%s: (id=%d) E1 " | ||
2445 | "lost frame sync\n", | ||
2446 | __func__, hc->id); | ||
2447 | hc->chan[hc->dslot].sync = 1; | ||
2448 | } | ||
2449 | break; | ||
2450 | } | ||
2451 | } | ||
2452 | |||
2453 | if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) | ||
2454 | hfcmulti_watchdog(hc); | ||
2455 | |||
2456 | if (hc->leds) | ||
2457 | hfcmulti_leds(hc); | ||
2458 | } | ||
2459 | |||
2460 | static void | ||
2461 | ph_state_irq(struct hfc_multi *hc, u_char r_irq_statech) | ||
2462 | { | ||
2463 | struct dchannel *dch; | ||
2464 | int ch; | ||
2465 | int active; | ||
2466 | u_char st_status, temp; | ||
2467 | |||
2468 | /* state machine */ | ||
2469 | for (ch = 0; ch <= 31; ch++) { | ||
2470 | if (hc->chan[ch].dch) { | ||
2471 | dch = hc->chan[ch].dch; | ||
2472 | if (r_irq_statech & 1) { | ||
2473 | HFC_outb_nodebug(hc, R_ST_SEL, | ||
2474 | hc->chan[ch].port); | ||
2475 | /* undocumented: delay after R_ST_SEL */ | ||
2476 | udelay(1); | ||
2477 | /* undocumented: status changes during read */ | ||
2478 | st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); | ||
2479 | while (st_status != (temp = | ||
2480 | HFC_inb_nodebug(hc, A_ST_RD_STATE))) { | ||
2481 | if (debug & DEBUG_HFCMULTI_STATE) | ||
2482 | printk(KERN_DEBUG "%s: reread " | ||
2483 | "STATE because %d!=%d\n", | ||
2484 | __func__, temp, | ||
2485 | st_status); | ||
2486 | st_status = temp; /* repeat */ | ||
2487 | } | ||
2488 | |||
2489 | /* Speech Design TE-sync indication */ | ||
2490 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && | ||
2491 | dch->dev.D.protocol == ISDN_P_TE_S0) { | ||
2492 | if (st_status & V_FR_SYNC_ST) | ||
2493 | hc->syncronized |= | ||
2494 | (1 << hc->chan[ch].port); | ||
2495 | else | ||
2496 | hc->syncronized &= | ||
2497 | ~(1 << hc->chan[ch].port); | ||
2498 | } | ||
2499 | dch->state = st_status & 0x0f; | ||
2500 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
2501 | active = 3; | ||
2502 | else | ||
2503 | active = 7; | ||
2504 | if (dch->state == active) { | ||
2505 | HFC_outb_nodebug(hc, R_FIFO, | ||
2506 | (ch << 1) | 1); | ||
2507 | HFC_wait_nodebug(hc); | ||
2508 | HFC_outb_nodebug(hc, | ||
2509 | R_INC_RES_FIFO, V_RES_F); | ||
2510 | HFC_wait_nodebug(hc); | ||
2511 | dch->tx_idx = 0; | ||
2512 | } | ||
2513 | schedule_event(dch, FLG_PHCHANGE); | ||
2514 | if (debug & DEBUG_HFCMULTI_STATE) | ||
2515 | printk(KERN_DEBUG | ||
2516 | "%s: S/T newstate %x port %d\n", | ||
2517 | __func__, dch->state, | ||
2518 | hc->chan[ch].port); | ||
2519 | } | ||
2520 | r_irq_statech >>= 1; | ||
2521 | } | ||
2522 | } | ||
2523 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | ||
2524 | plxsd_checksync(hc, 0); | ||
2525 | } | ||
2526 | |||
2527 | static void | ||
2528 | fifo_irq(struct hfc_multi *hc, int block) | ||
2529 | { | ||
2530 | int ch, j; | ||
2531 | struct dchannel *dch; | ||
2532 | struct bchannel *bch; | ||
2533 | u_char r_irq_fifo_bl; | ||
2534 | |||
2535 | r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block); | ||
2536 | j = 0; | ||
2537 | while (j < 8) { | ||
2538 | ch = (block << 2) + (j >> 1); | ||
2539 | dch = hc->chan[ch].dch; | ||
2540 | bch = hc->chan[ch].bch; | ||
2541 | if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) { | ||
2542 | j += 2; | ||
2543 | continue; | ||
2544 | } | ||
2545 | if (dch && (r_irq_fifo_bl & (1 << j)) && | ||
2546 | test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
2547 | hfcmulti_tx(hc, ch); | ||
2548 | /* start fifo */ | ||
2549 | HFC_outb_nodebug(hc, R_FIFO, 0); | ||
2550 | HFC_wait_nodebug(hc); | ||
2551 | } | ||
2552 | if (bch && (r_irq_fifo_bl & (1 << j)) && | ||
2553 | test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
2554 | hfcmulti_tx(hc, ch); | ||
2555 | /* start fifo */ | ||
2556 | HFC_outb_nodebug(hc, R_FIFO, 0); | ||
2557 | HFC_wait_nodebug(hc); | ||
2558 | } | ||
2559 | j++; | ||
2560 | if (dch && (r_irq_fifo_bl & (1 << j)) && | ||
2561 | test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
2562 | hfcmulti_rx(hc, ch); | ||
2563 | } | ||
2564 | if (bch && (r_irq_fifo_bl & (1 << j)) && | ||
2565 | test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
2566 | hfcmulti_rx(hc, ch); | ||
2567 | } | ||
2568 | j++; | ||
2569 | } | ||
2570 | } | ||
2571 | |||
2572 | #ifdef IRQ_DEBUG | ||
2573 | int irqsem; | ||
2574 | #endif | ||
2575 | static irqreturn_t | ||
2576 | hfcmulti_interrupt(int intno, void *dev_id) | ||
2577 | { | ||
2578 | #ifdef IRQCOUNT_DEBUG | ||
2579 | static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, | ||
2580 | iq5 = 0, iq6 = 0, iqcnt = 0; | ||
2581 | #endif | ||
2582 | static int count; | ||
2583 | struct hfc_multi *hc = dev_id; | ||
2584 | struct dchannel *dch; | ||
2585 | u_char r_irq_statech, status, r_irq_misc, r_irq_oview; | ||
2586 | int i; | ||
2587 | u_short *plx_acc, wval; | ||
2588 | u_char e1_syncsta, temp; | ||
2589 | u_long flags; | ||
2590 | |||
2591 | if (!hc) { | ||
2592 | printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); | ||
2593 | return IRQ_NONE; | ||
2594 | } | ||
2595 | |||
2596 | spin_lock(&hc->lock); | ||
2597 | |||
2598 | #ifdef IRQ_DEBUG | ||
2599 | if (irqsem) | ||
2600 | printk(KERN_ERR "irq for card %d during irq from " | ||
2601 | "card %d, this is no bug.\n", hc->id + 1, irqsem); | ||
2602 | irqsem = hc->id + 1; | ||
2603 | #endif | ||
2604 | |||
2605 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
2606 | spin_lock_irqsave(&plx_lock, flags); | ||
2607 | plx_acc = (u_short *)(hc->plx_membase + PLX_INTCSR); | ||
2608 | wval = readw(plx_acc); | ||
2609 | spin_unlock_irqrestore(&plx_lock, flags); | ||
2610 | if (!(wval & PLX_INTCSR_LINTI1_STATUS)) | ||
2611 | goto irq_notforus; | ||
2612 | } | ||
2613 | |||
2614 | status = HFC_inb_nodebug(hc, R_STATUS); | ||
2615 | r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); | ||
2616 | #ifdef IRQCOUNT_DEBUG | ||
2617 | if (r_irq_statech) | ||
2618 | iq1++; | ||
2619 | if (status & V_DTMF_STA) | ||
2620 | iq2++; | ||
2621 | if (status & V_LOST_STA) | ||
2622 | iq3++; | ||
2623 | if (status & V_EXT_IRQSTA) | ||
2624 | iq4++; | ||
2625 | if (status & V_MISC_IRQSTA) | ||
2626 | iq5++; | ||
2627 | if (status & V_FR_IRQSTA) | ||
2628 | iq6++; | ||
2629 | if (iqcnt++ > 5000) { | ||
2630 | printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n", | ||
2631 | iq1, iq2, iq3, iq4, iq5, iq6); | ||
2632 | iqcnt = 0; | ||
2633 | } | ||
2634 | #endif | ||
2635 | if (!r_irq_statech && | ||
2636 | !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | | ||
2637 | V_MISC_IRQSTA | V_FR_IRQSTA))) { | ||
2638 | /* irq is not for us */ | ||
2639 | goto irq_notforus; | ||
2640 | } | ||
2641 | hc->irqcnt++; | ||
2642 | if (r_irq_statech) { | ||
2643 | if (hc->type != 1) | ||
2644 | ph_state_irq(hc, r_irq_statech); | ||
2645 | } | ||
2646 | if (status & V_EXT_IRQSTA) | ||
2647 | ; /* external IRQ */ | ||
2648 | if (status & V_LOST_STA) { | ||
2649 | /* LOST IRQ */ | ||
2650 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */ | ||
2651 | } | ||
2652 | if (status & V_MISC_IRQSTA) { | ||
2653 | /* misc IRQ */ | ||
2654 | r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); | ||
2655 | if (r_irq_misc & V_STA_IRQ) { | ||
2656 | if (hc->type == 1) { | ||
2657 | /* state machine */ | ||
2658 | dch = hc->chan[hc->dslot].dch; | ||
2659 | e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); | ||
2660 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) | ||
2661 | && hc->e1_getclock) { | ||
2662 | if (e1_syncsta & V_FR_SYNC_E1) | ||
2663 | hc->syncronized = 1; | ||
2664 | else | ||
2665 | hc->syncronized = 0; | ||
2666 | } | ||
2667 | /* undocumented: status changes during read */ | ||
2668 | dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA); | ||
2669 | while (dch->state != (temp = | ||
2670 | HFC_inb_nodebug(hc, R_E1_RD_STA))) { | ||
2671 | if (debug & DEBUG_HFCMULTI_STATE) | ||
2672 | printk(KERN_DEBUG "%s: reread " | ||
2673 | "STATE because %d!=%d\n", | ||
2674 | __func__, temp, | ||
2675 | dch->state); | ||
2676 | dch->state = temp; /* repeat */ | ||
2677 | } | ||
2678 | dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) | ||
2679 | & 0x7; | ||
2680 | schedule_event(dch, FLG_PHCHANGE); | ||
2681 | if (debug & DEBUG_HFCMULTI_STATE) | ||
2682 | printk(KERN_DEBUG | ||
2683 | "%s: E1 (id=%d) newstate %x\n", | ||
2684 | __func__, hc->id, dch->state); | ||
2685 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | ||
2686 | plxsd_checksync(hc, 0); | ||
2687 | } | ||
2688 | } | ||
2689 | if (r_irq_misc & V_TI_IRQ) | ||
2690 | handle_timer_irq(hc); | ||
2691 | |||
2692 | if (r_irq_misc & V_DTMF_IRQ) { | ||
2693 | /* -> DTMF IRQ */ | ||
2694 | hfcmulti_dtmf(hc); | ||
2695 | } | ||
2696 | /* TODO: REPLACE !!!! 125 us Interrupts are not acceptable */ | ||
2697 | if (r_irq_misc & V_IRQ_PROC) { | ||
2698 | /* IRQ every 125us */ | ||
2699 | count++; | ||
2700 | /* generate 1kHz signal */ | ||
2701 | if (count == 8) { | ||
2702 | if (hfc_interrupt) | ||
2703 | hfc_interrupt(); | ||
2704 | count = 0; | ||
2705 | } | ||
2706 | } | ||
2707 | |||
2708 | } | ||
2709 | if (status & V_FR_IRQSTA) { | ||
2710 | /* FIFO IRQ */ | ||
2711 | r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); | ||
2712 | for (i = 0; i < 8; i++) { | ||
2713 | if (r_irq_oview & (1 << i)) | ||
2714 | fifo_irq(hc, i); | ||
2715 | } | ||
2716 | } | ||
2717 | |||
2718 | #ifdef IRQ_DEBUG | ||
2719 | irqsem = 0; | ||
2720 | #endif | ||
2721 | spin_unlock(&hc->lock); | ||
2722 | return IRQ_HANDLED; | ||
2723 | |||
2724 | irq_notforus: | ||
2725 | #ifdef IRQ_DEBUG | ||
2726 | irqsem = 0; | ||
2727 | #endif | ||
2728 | spin_unlock(&hc->lock); | ||
2729 | return IRQ_NONE; | ||
2730 | } | ||
2731 | |||
2732 | |||
2733 | /* | ||
2734 | * timer callback for D-chan busy resolution. Currently no function | ||
2735 | */ | ||
2736 | |||
2737 | static void | ||
2738 | hfcmulti_dbusy_timer(struct hfc_multi *hc) | ||
2739 | { | ||
2740 | } | ||
2741 | |||
2742 | |||
2743 | /* | ||
2744 | * activate/deactivate hardware for selected channels and mode | ||
2745 | * | ||
2746 | * configure B-channel with the given protocol | ||
2747 | * ch eqals to the HFC-channel (0-31) | ||
2748 | * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 | ||
2749 | * for S/T, 1-31 for E1) | ||
2750 | * the hdlc interrupts will be set/unset | ||
2751 | */ | ||
2752 | static int | ||
2753 | mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, | ||
2754 | int bank_tx, int slot_rx, int bank_rx) | ||
2755 | { | ||
2756 | int flow_tx = 0, flow_rx = 0, routing = 0; | ||
2757 | int oslot_tx, oslot_rx; | ||
2758 | int conf; | ||
2759 | |||
2760 | if (ch < 0 || ch > 31) | ||
2761 | return EINVAL; | ||
2762 | oslot_tx = hc->chan[ch].slot_tx; | ||
2763 | oslot_rx = hc->chan[ch].slot_rx; | ||
2764 | conf = hc->chan[ch].conf; | ||
2765 | |||
2766 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2767 | printk(KERN_DEBUG | ||
2768 | "%s: card %d channel %d protocol %x slot old=%d new=%d " | ||
2769 | "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n", | ||
2770 | __func__, hc->id, ch, protocol, oslot_tx, slot_tx, | ||
2771 | bank_tx, oslot_rx, slot_rx, bank_rx); | ||
2772 | |||
2773 | if (oslot_tx >= 0 && slot_tx != oslot_tx) { | ||
2774 | /* remove from slot */ | ||
2775 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2776 | printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", | ||
2777 | __func__, oslot_tx); | ||
2778 | if (hc->slot_owner[oslot_tx<<1] == ch) { | ||
2779 | HFC_outb(hc, R_SLOT, oslot_tx << 1); | ||
2780 | HFC_outb(hc, A_SL_CFG, 0); | ||
2781 | HFC_outb(hc, A_CONF, 0); | ||
2782 | hc->slot_owner[oslot_tx<<1] = -1; | ||
2783 | } else { | ||
2784 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2785 | printk(KERN_DEBUG | ||
2786 | "%s: we are not owner of this tx slot " | ||
2787 | "anymore, channel %d is.\n", | ||
2788 | __func__, hc->slot_owner[oslot_tx<<1]); | ||
2789 | } | ||
2790 | } | ||
2791 | |||
2792 | if (oslot_rx >= 0 && slot_rx != oslot_rx) { | ||
2793 | /* remove from slot */ | ||
2794 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2795 | printk(KERN_DEBUG | ||
2796 | "%s: remove from slot %d (RX)\n", | ||
2797 | __func__, oslot_rx); | ||
2798 | if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) { | ||
2799 | HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR); | ||
2800 | HFC_outb(hc, A_SL_CFG, 0); | ||
2801 | hc->slot_owner[(oslot_rx << 1) | 1] = -1; | ||
2802 | } else { | ||
2803 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2804 | printk(KERN_DEBUG | ||
2805 | "%s: we are not owner of this rx slot " | ||
2806 | "anymore, channel %d is.\n", | ||
2807 | __func__, | ||
2808 | hc->slot_owner[(oslot_rx << 1) | 1]); | ||
2809 | } | ||
2810 | } | ||
2811 | |||
2812 | if (slot_tx < 0) { | ||
2813 | flow_tx = 0x80; /* FIFO->ST */ | ||
2814 | /* disable pcm slot */ | ||
2815 | hc->chan[ch].slot_tx = -1; | ||
2816 | hc->chan[ch].bank_tx = 0; | ||
2817 | } else { | ||
2818 | /* set pcm slot */ | ||
2819 | if (hc->chan[ch].txpending) | ||
2820 | flow_tx = 0x80; /* FIFO->ST */ | ||
2821 | else | ||
2822 | flow_tx = 0xc0; /* PCM->ST */ | ||
2823 | /* put on slot */ | ||
2824 | routing = bank_tx ? 0xc0 : 0x80; | ||
2825 | if (conf >= 0 || bank_tx > 1) | ||
2826 | routing = 0x40; /* loop */ | ||
2827 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2828 | printk(KERN_DEBUG "%s: put channel %d to slot %d bank" | ||
2829 | " %d flow %02x routing %02x conf %d (TX)\n", | ||
2830 | __func__, ch, slot_tx, bank_tx, | ||
2831 | flow_tx, routing, conf); | ||
2832 | HFC_outb(hc, R_SLOT, slot_tx << 1); | ||
2833 | HFC_outb(hc, A_SL_CFG, (ch<<1) | routing); | ||
2834 | HFC_outb(hc, A_CONF, (conf < 0) ? 0 : (conf | V_CONF_SL)); | ||
2835 | hc->slot_owner[slot_tx << 1] = ch; | ||
2836 | hc->chan[ch].slot_tx = slot_tx; | ||
2837 | hc->chan[ch].bank_tx = bank_tx; | ||
2838 | } | ||
2839 | if (slot_rx < 0) { | ||
2840 | /* disable pcm slot */ | ||
2841 | flow_rx = 0x80; /* ST->FIFO */ | ||
2842 | hc->chan[ch].slot_rx = -1; | ||
2843 | hc->chan[ch].bank_rx = 0; | ||
2844 | } else { | ||
2845 | /* set pcm slot */ | ||
2846 | if (hc->chan[ch].txpending) | ||
2847 | flow_rx = 0x80; /* ST->FIFO */ | ||
2848 | else | ||
2849 | flow_rx = 0xc0; /* ST->(FIFO,PCM) */ | ||
2850 | /* put on slot */ | ||
2851 | routing = bank_rx?0x80:0xc0; /* reversed */ | ||
2852 | if (conf >= 0 || bank_rx > 1) | ||
2853 | routing = 0x40; /* loop */ | ||
2854 | if (debug & DEBUG_HFCMULTI_MODE) | ||
2855 | printk(KERN_DEBUG "%s: put channel %d to slot %d bank" | ||
2856 | " %d flow %02x routing %02x conf %d (RX)\n", | ||
2857 | __func__, ch, slot_rx, bank_rx, | ||
2858 | flow_rx, routing, conf); | ||
2859 | HFC_outb(hc, R_SLOT, (slot_rx<<1) | V_SL_DIR); | ||
2860 | HFC_outb(hc, A_SL_CFG, (ch<<1) | V_CH_DIR | routing); | ||
2861 | hc->slot_owner[(slot_rx<<1)|1] = ch; | ||
2862 | hc->chan[ch].slot_rx = slot_rx; | ||
2863 | hc->chan[ch].bank_rx = bank_rx; | ||
2864 | } | ||
2865 | |||
2866 | switch (protocol) { | ||
2867 | case (ISDN_P_NONE): | ||
2868 | /* disable TX fifo */ | ||
2869 | HFC_outb(hc, R_FIFO, ch << 1); | ||
2870 | HFC_wait(hc); | ||
2871 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); | ||
2872 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
2873 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
2874 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
2875 | HFC_wait(hc); | ||
2876 | /* disable RX fifo */ | ||
2877 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | ||
2878 | HFC_wait(hc); | ||
2879 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); | ||
2880 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
2881 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
2882 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
2883 | HFC_wait(hc); | ||
2884 | if (hc->chan[ch].bch && hc->type != 1) { | ||
2885 | hc->hw.a_st_ctrl0[hc->chan[ch].port] &= | ||
2886 | ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN; | ||
2887 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | ||
2888 | /* undocumented: delay after R_ST_SEL */ | ||
2889 | udelay(1); | ||
2890 | HFC_outb(hc, A_ST_CTRL0, | ||
2891 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | ||
2892 | } | ||
2893 | if (hc->chan[ch].bch) { | ||
2894 | test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); | ||
2895 | test_and_clear_bit(FLG_TRANSPARENT, | ||
2896 | &hc->chan[ch].bch->Flags); | ||
2897 | } | ||
2898 | break; | ||
2899 | case (ISDN_P_B_RAW): /* B-channel */ | ||
2900 | |||
2901 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | ||
2902 | (hc->chan[ch].slot_rx < 0) && | ||
2903 | (hc->chan[ch].slot_tx < 0)) { | ||
2904 | |||
2905 | printk(KERN_DEBUG | ||
2906 | "Setting B-channel %d to echo cancelable " | ||
2907 | "state on PCM slot %d\n", ch, | ||
2908 | ((ch / 4) * 8) + ((ch % 4) * 4) + 1); | ||
2909 | printk(KERN_DEBUG | ||
2910 | "Enabling pass through for channel\n"); | ||
2911 | vpm_out(hc, ch, ((ch / 4) * 8) + | ||
2912 | ((ch % 4) * 4) + 1, 0x01); | ||
2913 | /* rx path */ | ||
2914 | /* S/T -> PCM */ | ||
2915 | HFC_outb(hc, R_FIFO, (ch << 1)); | ||
2916 | HFC_wait(hc); | ||
2917 | HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); | ||
2918 | HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + | ||
2919 | ((ch % 4) * 4) + 1) << 1); | ||
2920 | HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1)); | ||
2921 | |||
2922 | /* PCM -> FIFO */ | ||
2923 | HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1); | ||
2924 | HFC_wait(hc); | ||
2925 | HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); | ||
2926 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
2927 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
2928 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
2929 | HFC_wait(hc); | ||
2930 | HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + | ||
2931 | ((ch % 4) * 4) + 1) << 1) | 1); | ||
2932 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); | ||
2933 | |||
2934 | /* tx path */ | ||
2935 | /* PCM -> S/T */ | ||
2936 | HFC_outb(hc, R_FIFO, (ch << 1) | 1); | ||
2937 | HFC_wait(hc); | ||
2938 | HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); | ||
2939 | HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + | ||
2940 | ((ch % 4) * 4)) << 1) | 1); | ||
2941 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1); | ||
2942 | |||
2943 | /* FIFO -> PCM */ | ||
2944 | HFC_outb(hc, R_FIFO, 0x20 | (ch << 1)); | ||
2945 | HFC_wait(hc); | ||
2946 | HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); | ||
2947 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
2948 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
2949 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
2950 | HFC_wait(hc); | ||
2951 | /* tx silence */ | ||
2952 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); | ||
2953 | HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + | ||
2954 | ((ch % 4) * 4)) << 1); | ||
2955 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); | ||
2956 | } else { | ||
2957 | /* enable TX fifo */ | ||
2958 | HFC_outb(hc, R_FIFO, ch << 1); | ||
2959 | HFC_wait(hc); | ||
2960 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | | ||
2961 | V_HDLC_TRP | V_IFF); | ||
2962 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
2963 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
2964 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
2965 | HFC_wait(hc); | ||
2966 | /* tx silence */ | ||
2967 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); | ||
2968 | /* enable RX fifo */ | ||
2969 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | ||
2970 | HFC_wait(hc); | ||
2971 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP); | ||
2972 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
2973 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
2974 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
2975 | HFC_wait(hc); | ||
2976 | } | ||
2977 | if (hc->type != 1) { | ||
2978 | hc->hw.a_st_ctrl0[hc->chan[ch].port] |= | ||
2979 | ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; | ||
2980 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | ||
2981 | /* undocumented: delay after R_ST_SEL */ | ||
2982 | udelay(1); | ||
2983 | HFC_outb(hc, A_ST_CTRL0, | ||
2984 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | ||
2985 | } | ||
2986 | if (hc->chan[ch].bch) | ||
2987 | test_and_set_bit(FLG_TRANSPARENT, | ||
2988 | &hc->chan[ch].bch->Flags); | ||
2989 | break; | ||
2990 | case (ISDN_P_B_HDLC): /* B-channel */ | ||
2991 | case (ISDN_P_TE_S0): /* D-channel */ | ||
2992 | case (ISDN_P_NT_S0): | ||
2993 | case (ISDN_P_TE_E1): | ||
2994 | case (ISDN_P_NT_E1): | ||
2995 | /* enable TX fifo */ | ||
2996 | HFC_outb(hc, R_FIFO, ch<<1); | ||
2997 | HFC_wait(hc); | ||
2998 | if (hc->type == 1 || hc->chan[ch].bch) { | ||
2999 | /* E1 or B-channel */ | ||
3000 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); | ||
3001 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
3002 | } else { | ||
3003 | /* D-Channel without HDLC fill flags */ | ||
3004 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); | ||
3005 | HFC_outb(hc, A_SUBCH_CFG, 2); | ||
3006 | } | ||
3007 | HFC_outb(hc, A_IRQ_MSK, V_IRQ); | ||
3008 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
3009 | HFC_wait(hc); | ||
3010 | /* enable RX fifo */ | ||
3011 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | ||
3012 | HFC_wait(hc); | ||
3013 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); | ||
3014 | if (hc->type == 1 || hc->chan[ch].bch) | ||
3015 | HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ | ||
3016 | else | ||
3017 | HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ | ||
3018 | HFC_outb(hc, A_IRQ_MSK, V_IRQ); | ||
3019 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
3020 | HFC_wait(hc); | ||
3021 | if (hc->chan[ch].bch) { | ||
3022 | test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); | ||
3023 | if (hc->type != 1) { | ||
3024 | hc->hw.a_st_ctrl0[hc->chan[ch].port] |= | ||
3025 | ((ch&0x3) == 0) ? V_B1_EN : V_B2_EN; | ||
3026 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | ||
3027 | /* undocumented: delay after R_ST_SEL */ | ||
3028 | udelay(1); | ||
3029 | HFC_outb(hc, A_ST_CTRL0, | ||
3030 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | ||
3031 | } | ||
3032 | } | ||
3033 | break; | ||
3034 | default: | ||
3035 | printk(KERN_DEBUG "%s: protocol not known %x\n", | ||
3036 | __func__, protocol); | ||
3037 | hc->chan[ch].protocol = ISDN_P_NONE; | ||
3038 | return -ENOPROTOOPT; | ||
3039 | } | ||
3040 | hc->chan[ch].protocol = protocol; | ||
3041 | return 0; | ||
3042 | } | ||
3043 | |||
3044 | |||
3045 | /* | ||
3046 | * connect/disconnect PCM | ||
3047 | */ | ||
3048 | |||
3049 | static void | ||
3050 | hfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx, | ||
3051 | int slot_rx, int bank_rx) | ||
3052 | { | ||
3053 | if (slot_rx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) { | ||
3054 | /* disable PCM */ | ||
3055 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0); | ||
3056 | return; | ||
3057 | } | ||
3058 | |||
3059 | /* enable pcm */ | ||
3060 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, | ||
3061 | slot_rx, bank_rx); | ||
3062 | } | ||
3063 | |||
3064 | /* | ||
3065 | * set/disable conference | ||
3066 | */ | ||
3067 | |||
3068 | static void | ||
3069 | hfcmulti_conf(struct hfc_multi *hc, int ch, int num) | ||
3070 | { | ||
3071 | if (num >= 0 && num <= 7) | ||
3072 | hc->chan[ch].conf = num; | ||
3073 | else | ||
3074 | hc->chan[ch].conf = -1; | ||
3075 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, | ||
3076 | hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, | ||
3077 | hc->chan[ch].bank_rx); | ||
3078 | } | ||
3079 | |||
3080 | |||
3081 | /* | ||
3082 | * set/disable sample loop | ||
3083 | */ | ||
3084 | |||
3085 | /* NOTE: this function is experimental and therefore disabled */ | ||
3086 | |||
3087 | /* | ||
3088 | * Layer 1 callback function | ||
3089 | */ | ||
3090 | static int | ||
3091 | hfcm_l1callback(struct dchannel *dch, u_int cmd) | ||
3092 | { | ||
3093 | struct hfc_multi *hc = dch->hw; | ||
3094 | u_long flags; | ||
3095 | |||
3096 | switch (cmd) { | ||
3097 | case INFO3_P8: | ||
3098 | case INFO3_P10: | ||
3099 | break; | ||
3100 | case HW_RESET_REQ: | ||
3101 | /* start activation */ | ||
3102 | spin_lock_irqsave(&hc->lock, flags); | ||
3103 | if (hc->type == 1) { | ||
3104 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3105 | printk(KERN_DEBUG | ||
3106 | "%s: HW_RESET_REQ no BRI\n", | ||
3107 | __func__); | ||
3108 | } else { | ||
3109 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | ||
3110 | /* undocumented: delay after R_ST_SEL */ | ||
3111 | udelay(1); | ||
3112 | HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */ | ||
3113 | udelay(6); /* wait at least 5,21us */ | ||
3114 | HFC_outb(hc, A_ST_WR_STATE, 3); | ||
3115 | HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT*3)); | ||
3116 | /* activate */ | ||
3117 | } | ||
3118 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3119 | l1_event(dch->l1, HW_POWERUP_IND); | ||
3120 | break; | ||
3121 | case HW_DEACT_REQ: | ||
3122 | /* start deactivation */ | ||
3123 | spin_lock_irqsave(&hc->lock, flags); | ||
3124 | if (hc->type == 1) { | ||
3125 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3126 | printk(KERN_DEBUG | ||
3127 | "%s: HW_DEACT_REQ no BRI\n", | ||
3128 | __func__); | ||
3129 | } else { | ||
3130 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | ||
3131 | /* undocumented: delay after R_ST_SEL */ | ||
3132 | udelay(1); | ||
3133 | HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); | ||
3134 | /* deactivate */ | ||
3135 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
3136 | hc->syncronized &= | ||
3137 | ~(1 << hc->chan[dch->slot].port); | ||
3138 | plxsd_checksync(hc, 0); | ||
3139 | } | ||
3140 | } | ||
3141 | skb_queue_purge(&dch->squeue); | ||
3142 | if (dch->tx_skb) { | ||
3143 | dev_kfree_skb(dch->tx_skb); | ||
3144 | dch->tx_skb = NULL; | ||
3145 | } | ||
3146 | dch->tx_idx = 0; | ||
3147 | if (dch->rx_skb) { | ||
3148 | dev_kfree_skb(dch->rx_skb); | ||
3149 | dch->rx_skb = NULL; | ||
3150 | } | ||
3151 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
3152 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
3153 | del_timer(&dch->timer); | ||
3154 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3155 | break; | ||
3156 | case HW_POWERUP_REQ: | ||
3157 | spin_lock_irqsave(&hc->lock, flags); | ||
3158 | if (hc->type == 1) { | ||
3159 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3160 | printk(KERN_DEBUG | ||
3161 | "%s: HW_POWERUP_REQ no BRI\n", | ||
3162 | __func__); | ||
3163 | } else { | ||
3164 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | ||
3165 | /* undocumented: delay after R_ST_SEL */ | ||
3166 | udelay(1); | ||
3167 | HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ | ||
3168 | udelay(6); /* wait at least 5,21us */ | ||
3169 | HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ | ||
3170 | } | ||
3171 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3172 | break; | ||
3173 | case PH_ACTIVATE_IND: | ||
3174 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
3175 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
3176 | GFP_ATOMIC); | ||
3177 | break; | ||
3178 | case PH_DEACTIVATE_IND: | ||
3179 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
3180 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
3181 | GFP_ATOMIC); | ||
3182 | break; | ||
3183 | default: | ||
3184 | if (dch->debug & DEBUG_HW) | ||
3185 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
3186 | __func__, cmd); | ||
3187 | return -1; | ||
3188 | } | ||
3189 | return 0; | ||
3190 | } | ||
3191 | |||
3192 | /* | ||
3193 | * Layer2 -> Layer 1 Transfer | ||
3194 | */ | ||
3195 | |||
3196 | static int | ||
3197 | handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
3198 | { | ||
3199 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
3200 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
3201 | struct hfc_multi *hc = dch->hw; | ||
3202 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
3203 | int ret = -EINVAL; | ||
3204 | unsigned int id; | ||
3205 | u_long flags; | ||
3206 | |||
3207 | switch (hh->prim) { | ||
3208 | case PH_DATA_REQ: | ||
3209 | if (skb->len < 1) | ||
3210 | break; | ||
3211 | spin_lock_irqsave(&hc->lock, flags); | ||
3212 | ret = dchannel_senddata(dch, skb); | ||
3213 | if (ret > 0) { /* direct TX */ | ||
3214 | id = hh->id; /* skb can be freed */ | ||
3215 | hfcmulti_tx(hc, dch->slot); | ||
3216 | ret = 0; | ||
3217 | /* start fifo */ | ||
3218 | HFC_outb(hc, R_FIFO, 0); | ||
3219 | HFC_wait(hc); | ||
3220 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3221 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
3222 | } else | ||
3223 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3224 | return ret; | ||
3225 | case PH_ACTIVATE_REQ: | ||
3226 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | ||
3227 | spin_lock_irqsave(&hc->lock, flags); | ||
3228 | ret = 0; | ||
3229 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3230 | printk(KERN_DEBUG | ||
3231 | "%s: PH_ACTIVATE port %d (0..%d)\n", | ||
3232 | __func__, hc->chan[dch->slot].port, | ||
3233 | hc->ports-1); | ||
3234 | /* start activation */ | ||
3235 | if (hc->type == 1) { | ||
3236 | ph_state_change(dch); | ||
3237 | if (debug & DEBUG_HFCMULTI_STATE) | ||
3238 | printk(KERN_DEBUG | ||
3239 | "%s: E1 report state %x \n", | ||
3240 | __func__, dch->state); | ||
3241 | } else { | ||
3242 | HFC_outb(hc, R_ST_SEL, | ||
3243 | hc->chan[dch->slot].port); | ||
3244 | /* undocumented: delay after R_ST_SEL */ | ||
3245 | udelay(1); | ||
3246 | HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); | ||
3247 | /* G1 */ | ||
3248 | udelay(6); /* wait at least 5,21us */ | ||
3249 | HFC_outb(hc, A_ST_WR_STATE, 1); | ||
3250 | HFC_outb(hc, A_ST_WR_STATE, 1 | | ||
3251 | (V_ST_ACT*3)); /* activate */ | ||
3252 | dch->state = 1; | ||
3253 | } | ||
3254 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3255 | } else | ||
3256 | ret = l1_event(dch->l1, hh->prim); | ||
3257 | break; | ||
3258 | case PH_DEACTIVATE_REQ: | ||
3259 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
3260 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | ||
3261 | spin_lock_irqsave(&hc->lock, flags); | ||
3262 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3263 | printk(KERN_DEBUG | ||
3264 | "%s: PH_DEACTIVATE port %d (0..%d)\n", | ||
3265 | __func__, hc->chan[dch->slot].port, | ||
3266 | hc->ports-1); | ||
3267 | /* start deactivation */ | ||
3268 | if (hc->type == 1) { | ||
3269 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3270 | printk(KERN_DEBUG | ||
3271 | "%s: PH_DEACTIVATE no BRI\n", | ||
3272 | __func__); | ||
3273 | } else { | ||
3274 | HFC_outb(hc, R_ST_SEL, | ||
3275 | hc->chan[dch->slot].port); | ||
3276 | /* undocumented: delay after R_ST_SEL */ | ||
3277 | udelay(1); | ||
3278 | HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); | ||
3279 | /* deactivate */ | ||
3280 | dch->state = 1; | ||
3281 | } | ||
3282 | skb_queue_purge(&dch->squeue); | ||
3283 | if (dch->tx_skb) { | ||
3284 | dev_kfree_skb(dch->tx_skb); | ||
3285 | dch->tx_skb = NULL; | ||
3286 | } | ||
3287 | dch->tx_idx = 0; | ||
3288 | if (dch->rx_skb) { | ||
3289 | dev_kfree_skb(dch->rx_skb); | ||
3290 | dch->rx_skb = NULL; | ||
3291 | } | ||
3292 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
3293 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
3294 | del_timer(&dch->timer); | ||
3295 | #ifdef FIXME | ||
3296 | if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) | ||
3297 | dchannel_sched_event(&hc->dch, D_CLEARBUSY); | ||
3298 | #endif | ||
3299 | ret = 0; | ||
3300 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3301 | } else | ||
3302 | ret = l1_event(dch->l1, hh->prim); | ||
3303 | break; | ||
3304 | } | ||
3305 | if (!ret) | ||
3306 | dev_kfree_skb(skb); | ||
3307 | return ret; | ||
3308 | } | ||
3309 | |||
3310 | static void | ||
3311 | deactivate_bchannel(struct bchannel *bch) | ||
3312 | { | ||
3313 | struct hfc_multi *hc = bch->hw; | ||
3314 | u_long flags; | ||
3315 | |||
3316 | spin_lock_irqsave(&hc->lock, flags); | ||
3317 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
3318 | dev_kfree_skb(bch->next_skb); | ||
3319 | bch->next_skb = NULL; | ||
3320 | } | ||
3321 | if (bch->tx_skb) { | ||
3322 | dev_kfree_skb(bch->tx_skb); | ||
3323 | bch->tx_skb = NULL; | ||
3324 | } | ||
3325 | bch->tx_idx = 0; | ||
3326 | if (bch->rx_skb) { | ||
3327 | dev_kfree_skb(bch->rx_skb); | ||
3328 | bch->rx_skb = NULL; | ||
3329 | } | ||
3330 | hc->chan[bch->slot].coeff_count = 0; | ||
3331 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
3332 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
3333 | hc->chan[bch->slot].rx_off = 0; | ||
3334 | hc->chan[bch->slot].conf = -1; | ||
3335 | mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); | ||
3336 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3337 | } | ||
3338 | |||
3339 | static int | ||
3340 | handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
3341 | { | ||
3342 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
3343 | struct hfc_multi *hc = bch->hw; | ||
3344 | int ret = -EINVAL; | ||
3345 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
3346 | unsigned int id; | ||
3347 | u_long flags; | ||
3348 | |||
3349 | switch (hh->prim) { | ||
3350 | case PH_DATA_REQ: | ||
3351 | if (!skb->len) | ||
3352 | break; | ||
3353 | spin_lock_irqsave(&hc->lock, flags); | ||
3354 | ret = bchannel_senddata(bch, skb); | ||
3355 | if (ret > 0) { /* direct TX */ | ||
3356 | id = hh->id; /* skb can be freed */ | ||
3357 | hfcmulti_tx(hc, bch->slot); | ||
3358 | ret = 0; | ||
3359 | /* start fifo */ | ||
3360 | HFC_outb_nodebug(hc, R_FIFO, 0); | ||
3361 | HFC_wait_nodebug(hc); | ||
3362 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) { | ||
3363 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3364 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
3365 | } else | ||
3366 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3367 | } else | ||
3368 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3369 | return ret; | ||
3370 | case PH_ACTIVATE_REQ: | ||
3371 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3372 | printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", | ||
3373 | __func__, bch->slot); | ||
3374 | spin_lock_irqsave(&hc->lock, flags); | ||
3375 | /* activate B-channel if not already activated */ | ||
3376 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { | ||
3377 | hc->chan[bch->slot].txpending = 0; | ||
3378 | ret = mode_hfcmulti(hc, bch->slot, | ||
3379 | ch->protocol, | ||
3380 | hc->chan[bch->slot].slot_tx, | ||
3381 | hc->chan[bch->slot].bank_tx, | ||
3382 | hc->chan[bch->slot].slot_rx, | ||
3383 | hc->chan[bch->slot].bank_rx); | ||
3384 | if (!ret) { | ||
3385 | if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf | ||
3386 | && test_bit(HFC_CHIP_DTMF, &hc->chip)) { | ||
3387 | /* start decoder */ | ||
3388 | hc->dtmf = 1; | ||
3389 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
3390 | printk(KERN_DEBUG | ||
3391 | "%s: start dtmf decoder\n", | ||
3392 | __func__); | ||
3393 | HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | | ||
3394 | V_RST_DTMF); | ||
3395 | } | ||
3396 | } | ||
3397 | } else | ||
3398 | ret = 0; | ||
3399 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3400 | if (!ret) | ||
3401 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, | ||
3402 | GFP_KERNEL); | ||
3403 | break; | ||
3404 | case PH_CONTROL_REQ: | ||
3405 | spin_lock_irqsave(&hc->lock, flags); | ||
3406 | switch (hh->id) { | ||
3407 | case HFC_SPL_LOOP_ON: /* set sample loop */ | ||
3408 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3409 | printk(KERN_DEBUG | ||
3410 | "%s: HFC_SPL_LOOP_ON (len = %d)\n", | ||
3411 | __func__, skb->len); | ||
3412 | ret = 0; | ||
3413 | break; | ||
3414 | case HFC_SPL_LOOP_OFF: /* set silence */ | ||
3415 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3416 | printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n", | ||
3417 | __func__); | ||
3418 | ret = 0; | ||
3419 | break; | ||
3420 | default: | ||
3421 | printk(KERN_ERR | ||
3422 | "%s: unknown PH_CONTROL_REQ info %x\n", | ||
3423 | __func__, hh->id); | ||
3424 | ret = -EINVAL; | ||
3425 | } | ||
3426 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3427 | break; | ||
3428 | case PH_DEACTIVATE_REQ: | ||
3429 | deactivate_bchannel(bch); /* locked there */ | ||
3430 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, | ||
3431 | GFP_KERNEL); | ||
3432 | ret = 0; | ||
3433 | break; | ||
3434 | } | ||
3435 | if (!ret) | ||
3436 | dev_kfree_skb(skb); | ||
3437 | return ret; | ||
3438 | } | ||
3439 | |||
3440 | /* | ||
3441 | * bchannel control function | ||
3442 | */ | ||
3443 | static int | ||
3444 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
3445 | { | ||
3446 | int ret = 0; | ||
3447 | struct dsp_features *features = | ||
3448 | (struct dsp_features *)(*((u_long *)&cq->p1)); | ||
3449 | struct hfc_multi *hc = bch->hw; | ||
3450 | int slot_tx; | ||
3451 | int bank_tx; | ||
3452 | int slot_rx; | ||
3453 | int bank_rx; | ||
3454 | int num; | ||
3455 | |||
3456 | switch (cq->op) { | ||
3457 | case MISDN_CTRL_GETOP: | ||
3458 | cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | ||
3459 | | MISDN_CTRL_RX_OFF; | ||
3460 | break; | ||
3461 | case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ | ||
3462 | hc->chan[bch->slot].rx_off = !!cq->p1; | ||
3463 | if (!hc->chan[bch->slot].rx_off) { | ||
3464 | /* reset fifo on rx on */ | ||
3465 | HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1); | ||
3466 | HFC_wait_nodebug(hc); | ||
3467 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | ||
3468 | HFC_wait_nodebug(hc); | ||
3469 | } | ||
3470 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3471 | printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", | ||
3472 | __func__, bch->nr, hc->chan[bch->slot].rx_off); | ||
3473 | break; | ||
3474 | case MISDN_CTRL_HW_FEATURES: /* fill features structure */ | ||
3475 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3476 | printk(KERN_DEBUG "%s: HW_FEATURE request\n", | ||
3477 | __func__); | ||
3478 | /* create confirm */ | ||
3479 | features->hfc_id = hc->id; | ||
3480 | if (test_bit(HFC_CHIP_DTMF, &hc->chip)) | ||
3481 | features->hfc_dtmf = 1; | ||
3482 | features->hfc_loops = 0; | ||
3483 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | ||
3484 | features->hfc_echocanhw = 1; | ||
3485 | } else { | ||
3486 | features->pcm_id = hc->pcm; | ||
3487 | features->pcm_slots = hc->slots; | ||
3488 | features->pcm_banks = 2; | ||
3489 | } | ||
3490 | break; | ||
3491 | case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */ | ||
3492 | slot_tx = cq->p1 & 0xff; | ||
3493 | bank_tx = cq->p1 >> 8; | ||
3494 | slot_rx = cq->p2 & 0xff; | ||
3495 | bank_rx = cq->p2 >> 8; | ||
3496 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3497 | printk(KERN_DEBUG | ||
3498 | "%s: HFC_PCM_CONN slot %d bank %d (TX) " | ||
3499 | "slot %d bank %d (RX)\n", | ||
3500 | __func__, slot_tx, bank_tx, | ||
3501 | slot_rx, bank_rx); | ||
3502 | if (slot_tx < hc->slots && bank_tx <= 2 && | ||
3503 | slot_rx < hc->slots && bank_rx <= 2) | ||
3504 | hfcmulti_pcm(hc, bch->slot, | ||
3505 | slot_tx, bank_tx, slot_rx, bank_rx); | ||
3506 | else { | ||
3507 | printk(KERN_WARNING | ||
3508 | "%s: HFC_PCM_CONN slot %d bank %d (TX) " | ||
3509 | "slot %d bank %d (RX) out of range\n", | ||
3510 | __func__, slot_tx, bank_tx, | ||
3511 | slot_rx, bank_rx); | ||
3512 | ret = -EINVAL; | ||
3513 | } | ||
3514 | break; | ||
3515 | case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */ | ||
3516 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3517 | printk(KERN_DEBUG "%s: HFC_PCM_DISC\n", | ||
3518 | __func__); | ||
3519 | hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0); | ||
3520 | break; | ||
3521 | case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */ | ||
3522 | num = cq->p1 & 0xff; | ||
3523 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3524 | printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n", | ||
3525 | __func__, num); | ||
3526 | if (num <= 7) | ||
3527 | hfcmulti_conf(hc, bch->slot, num); | ||
3528 | else { | ||
3529 | printk(KERN_WARNING | ||
3530 | "%s: HW_CONF_JOIN conf %d out of range\n", | ||
3531 | __func__, num); | ||
3532 | ret = -EINVAL; | ||
3533 | } | ||
3534 | break; | ||
3535 | case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */ | ||
3536 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3537 | printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__); | ||
3538 | hfcmulti_conf(hc, bch->slot, -1); | ||
3539 | break; | ||
3540 | case MISDN_CTRL_HFC_ECHOCAN_ON: | ||
3541 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3542 | printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__); | ||
3543 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | ||
3544 | vpm_echocan_on(hc, bch->slot, cq->p1); | ||
3545 | else | ||
3546 | ret = -EINVAL; | ||
3547 | break; | ||
3548 | |||
3549 | case MISDN_CTRL_HFC_ECHOCAN_OFF: | ||
3550 | if (debug & DEBUG_HFCMULTI_MSG) | ||
3551 | printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n", | ||
3552 | __func__); | ||
3553 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | ||
3554 | vpm_echocan_off(hc, bch->slot); | ||
3555 | else | ||
3556 | ret = -EINVAL; | ||
3557 | break; | ||
3558 | default: | ||
3559 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
3560 | __func__, cq->op); | ||
3561 | ret = -EINVAL; | ||
3562 | break; | ||
3563 | } | ||
3564 | return ret; | ||
3565 | } | ||
3566 | |||
3567 | static int | ||
3568 | hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
3569 | { | ||
3570 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
3571 | struct hfc_multi *hc = bch->hw; | ||
3572 | int err = -EINVAL; | ||
3573 | u_long flags; | ||
3574 | |||
3575 | if (bch->debug & DEBUG_HW) | ||
3576 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
3577 | __func__, cmd, arg); | ||
3578 | switch (cmd) { | ||
3579 | case CLOSE_CHANNEL: | ||
3580 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
3581 | if (test_bit(FLG_ACTIVE, &bch->Flags)) | ||
3582 | deactivate_bchannel(bch); /* locked there */ | ||
3583 | ch->protocol = ISDN_P_NONE; | ||
3584 | ch->peer = NULL; | ||
3585 | module_put(THIS_MODULE); | ||
3586 | err = 0; | ||
3587 | break; | ||
3588 | case CONTROL_CHANNEL: | ||
3589 | spin_lock_irqsave(&hc->lock, flags); | ||
3590 | err = channel_bctrl(bch, arg); | ||
3591 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3592 | break; | ||
3593 | default: | ||
3594 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
3595 | __func__, cmd); | ||
3596 | } | ||
3597 | return err; | ||
3598 | } | ||
3599 | |||
3600 | /* | ||
3601 | * handle D-channel events | ||
3602 | * | ||
3603 | * handle state change event | ||
3604 | */ | ||
3605 | static void | ||
3606 | ph_state_change(struct dchannel *dch) | ||
3607 | { | ||
3608 | struct hfc_multi *hc = dch->hw; | ||
3609 | int ch, i; | ||
3610 | |||
3611 | if (!dch) { | ||
3612 | printk(KERN_WARNING "%s: ERROR given dch is NULL\n", | ||
3613 | __func__); | ||
3614 | return; | ||
3615 | } | ||
3616 | ch = dch->slot; | ||
3617 | |||
3618 | if (hc->type == 1) { | ||
3619 | if (dch->dev.D.protocol == ISDN_P_TE_E1) { | ||
3620 | if (debug & DEBUG_HFCMULTI_STATE) | ||
3621 | printk(KERN_DEBUG | ||
3622 | "%s: E1 TE (id=%d) newstate %x\n", | ||
3623 | __func__, hc->id, dch->state); | ||
3624 | } else { | ||
3625 | if (debug & DEBUG_HFCMULTI_STATE) | ||
3626 | printk(KERN_DEBUG | ||
3627 | "%s: E1 NT (id=%d) newstate %x\n", | ||
3628 | __func__, hc->id, dch->state); | ||
3629 | } | ||
3630 | switch (dch->state) { | ||
3631 | case (1): | ||
3632 | if (hc->e1_state != 1) { | ||
3633 | for (i = 1; i <= 31; i++) { | ||
3634 | /* reset fifos on e1 activation */ | ||
3635 | HFC_outb_nodebug(hc, R_FIFO, (i << 1) | 1); | ||
3636 | HFC_wait_nodebug(hc); | ||
3637 | HFC_outb_nodebug(hc, | ||
3638 | R_INC_RES_FIFO, V_RES_F); | ||
3639 | HFC_wait_nodebug(hc); | ||
3640 | } | ||
3641 | } | ||
3642 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
3643 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
3644 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
3645 | break; | ||
3646 | |||
3647 | default: | ||
3648 | if (hc->e1_state != 1) | ||
3649 | return; | ||
3650 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
3651 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | ||
3652 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
3653 | } | ||
3654 | hc->e1_state = dch->state; | ||
3655 | } else { | ||
3656 | if (dch->dev.D.protocol == ISDN_P_TE_S0) { | ||
3657 | if (debug & DEBUG_HFCMULTI_STATE) | ||
3658 | printk(KERN_DEBUG | ||
3659 | "%s: S/T TE newstate %x\n", | ||
3660 | __func__, dch->state); | ||
3661 | switch (dch->state) { | ||
3662 | case (0): | ||
3663 | l1_event(dch->l1, HW_RESET_IND); | ||
3664 | break; | ||
3665 | case (3): | ||
3666 | l1_event(dch->l1, HW_DEACT_IND); | ||
3667 | break; | ||
3668 | case (5): | ||
3669 | case (8): | ||
3670 | l1_event(dch->l1, ANYSIGNAL); | ||
3671 | break; | ||
3672 | case (6): | ||
3673 | l1_event(dch->l1, INFO2); | ||
3674 | break; | ||
3675 | case (7): | ||
3676 | l1_event(dch->l1, INFO4_P8); | ||
3677 | break; | ||
3678 | } | ||
3679 | } else { | ||
3680 | if (debug & DEBUG_HFCMULTI_STATE) | ||
3681 | printk(KERN_DEBUG "%s: S/T NT newstate %x\n", | ||
3682 | __func__, dch->state); | ||
3683 | switch (dch->state) { | ||
3684 | case (2): | ||
3685 | if (hc->chan[ch].nt_timer == 0) { | ||
3686 | hc->chan[ch].nt_timer = -1; | ||
3687 | HFC_outb(hc, R_ST_SEL, | ||
3688 | hc->chan[ch].port); | ||
3689 | /* undocumented: delay after R_ST_SEL */ | ||
3690 | udelay(1); | ||
3691 | HFC_outb(hc, A_ST_WR_STATE, 4 | | ||
3692 | V_ST_LD_STA); /* G4 */ | ||
3693 | udelay(6); /* wait at least 5,21us */ | ||
3694 | HFC_outb(hc, A_ST_WR_STATE, 4); | ||
3695 | dch->state = 4; | ||
3696 | } else { | ||
3697 | /* one extra count for the next event */ | ||
3698 | hc->chan[ch].nt_timer = | ||
3699 | nt_t1_count[poll_timer] + 1; | ||
3700 | HFC_outb(hc, R_ST_SEL, | ||
3701 | hc->chan[ch].port); | ||
3702 | /* undocumented: delay after R_ST_SEL */ | ||
3703 | udelay(1); | ||
3704 | /* allow G2 -> G3 transition */ | ||
3705 | HFC_outb(hc, A_ST_WR_STATE, 2 | | ||
3706 | V_SET_G2_G3); | ||
3707 | } | ||
3708 | break; | ||
3709 | case (1): | ||
3710 | hc->chan[ch].nt_timer = -1; | ||
3711 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
3712 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | ||
3713 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
3714 | break; | ||
3715 | case (4): | ||
3716 | hc->chan[ch].nt_timer = -1; | ||
3717 | break; | ||
3718 | case (3): | ||
3719 | hc->chan[ch].nt_timer = -1; | ||
3720 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
3721 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
3722 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
3723 | break; | ||
3724 | } | ||
3725 | } | ||
3726 | } | ||
3727 | } | ||
3728 | |||
3729 | /* | ||
3730 | * called for card mode init message | ||
3731 | */ | ||
3732 | |||
3733 | static void | ||
3734 | hfcmulti_initmode(struct dchannel *dch) | ||
3735 | { | ||
3736 | struct hfc_multi *hc = dch->hw; | ||
3737 | u_char a_st_wr_state, r_e1_wr_sta; | ||
3738 | int i, pt; | ||
3739 | |||
3740 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3741 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
3742 | |||
3743 | if (hc->type == 1) { | ||
3744 | hc->chan[hc->dslot].slot_tx = -1; | ||
3745 | hc->chan[hc->dslot].slot_rx = -1; | ||
3746 | hc->chan[hc->dslot].conf = -1; | ||
3747 | if (hc->dslot) { | ||
3748 | mode_hfcmulti(hc, hc->dslot, dch->dev.D.protocol, | ||
3749 | -1, 0, -1, 0); | ||
3750 | dch->timer.function = (void *) hfcmulti_dbusy_timer; | ||
3751 | dch->timer.data = (long) dch; | ||
3752 | init_timer(&dch->timer); | ||
3753 | } | ||
3754 | for (i = 1; i <= 31; i++) { | ||
3755 | if (i == hc->dslot) | ||
3756 | continue; | ||
3757 | hc->chan[i].slot_tx = -1; | ||
3758 | hc->chan[i].slot_rx = -1; | ||
3759 | hc->chan[i].conf = -1; | ||
3760 | mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); | ||
3761 | } | ||
3762 | /* E1 */ | ||
3763 | if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { | ||
3764 | HFC_outb(hc, R_LOS0, 255); /* 2 ms */ | ||
3765 | HFC_outb(hc, R_LOS1, 255); /* 512 ms */ | ||
3766 | } | ||
3767 | if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dslot].cfg)) { | ||
3768 | HFC_outb(hc, R_RX0, 0); | ||
3769 | hc->hw.r_tx0 = 0 | V_OUT_EN; | ||
3770 | } else { | ||
3771 | HFC_outb(hc, R_RX0, 1); | ||
3772 | hc->hw.r_tx0 = 1 | V_OUT_EN; | ||
3773 | } | ||
3774 | hc->hw.r_tx1 = V_ATX | V_NTRI; | ||
3775 | HFC_outb(hc, R_TX0, hc->hw.r_tx0); | ||
3776 | HFC_outb(hc, R_TX1, hc->hw.r_tx1); | ||
3777 | HFC_outb(hc, R_TX_FR0, 0x00); | ||
3778 | HFC_outb(hc, R_TX_FR1, 0xf8); | ||
3779 | |||
3780 | if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) | ||
3781 | HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); | ||
3782 | |||
3783 | HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); | ||
3784 | |||
3785 | if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) | ||
3786 | HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); | ||
3787 | |||
3788 | if (dch->dev.D.protocol == ISDN_P_NT_E1) { | ||
3789 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3790 | printk(KERN_DEBUG "%s: E1 port is NT-mode\n", | ||
3791 | __func__); | ||
3792 | r_e1_wr_sta = 0; /* G0 */ | ||
3793 | hc->e1_getclock = 0; | ||
3794 | } else { | ||
3795 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3796 | printk(KERN_DEBUG "%s: E1 port is TE-mode\n", | ||
3797 | __func__); | ||
3798 | r_e1_wr_sta = 0; /* F0 */ | ||
3799 | hc->e1_getclock = 1; | ||
3800 | } | ||
3801 | if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) | ||
3802 | HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); | ||
3803 | else | ||
3804 | HFC_outb(hc, R_SYNC_OUT, 0); | ||
3805 | if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip)) | ||
3806 | hc->e1_getclock = 1; | ||
3807 | if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip)) | ||
3808 | hc->e1_getclock = 0; | ||
3809 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
3810 | /* SLAVE (clock master) */ | ||
3811 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3812 | printk(KERN_DEBUG | ||
3813 | "%s: E1 port is clock master " | ||
3814 | "(clock from PCM)\n", __func__); | ||
3815 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); | ||
3816 | } else { | ||
3817 | if (hc->e1_getclock) { | ||
3818 | /* MASTER (clock slave) */ | ||
3819 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3820 | printk(KERN_DEBUG | ||
3821 | "%s: E1 port is clock slave " | ||
3822 | "(clock to PCM)\n", __func__); | ||
3823 | HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); | ||
3824 | } else { | ||
3825 | /* MASTER (clock master) */ | ||
3826 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3827 | printk(KERN_DEBUG "%s: E1 port is " | ||
3828 | "clock master " | ||
3829 | "(clock from QUARTZ)\n", | ||
3830 | __func__); | ||
3831 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | | ||
3832 | V_PCM_SYNC | V_JATT_OFF); | ||
3833 | HFC_outb(hc, R_SYNC_OUT, 0); | ||
3834 | } | ||
3835 | } | ||
3836 | HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */ | ||
3837 | HFC_outb(hc, R_PWM_MD, V_PWM0_MD); | ||
3838 | HFC_outb(hc, R_PWM0, 0x50); | ||
3839 | HFC_outb(hc, R_PWM1, 0xff); | ||
3840 | /* state machine setup */ | ||
3841 | HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); | ||
3842 | udelay(6); /* wait at least 5,21us */ | ||
3843 | HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); | ||
3844 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
3845 | hc->syncronized = 0; | ||
3846 | plxsd_checksync(hc, 0); | ||
3847 | } | ||
3848 | } else { | ||
3849 | i = dch->slot; | ||
3850 | hc->chan[i].slot_tx = -1; | ||
3851 | hc->chan[i].slot_rx = -1; | ||
3852 | hc->chan[i].conf = -1; | ||
3853 | mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); | ||
3854 | dch->timer.function = (void *)hfcmulti_dbusy_timer; | ||
3855 | dch->timer.data = (long) dch; | ||
3856 | init_timer(&dch->timer); | ||
3857 | hc->chan[i - 2].slot_tx = -1; | ||
3858 | hc->chan[i - 2].slot_rx = -1; | ||
3859 | hc->chan[i - 2].conf = -1; | ||
3860 | mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0); | ||
3861 | hc->chan[i - 1].slot_tx = -1; | ||
3862 | hc->chan[i - 1].slot_rx = -1; | ||
3863 | hc->chan[i - 1].conf = -1; | ||
3864 | mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); | ||
3865 | /* ST */ | ||
3866 | pt = hc->chan[i].port; | ||
3867 | /* select interface */ | ||
3868 | HFC_outb(hc, R_ST_SEL, pt); | ||
3869 | /* undocumented: delay after R_ST_SEL */ | ||
3870 | udelay(1); | ||
3871 | if (dch->dev.D.protocol == ISDN_P_NT_S0) { | ||
3872 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3873 | printk(KERN_DEBUG | ||
3874 | "%s: ST port %d is NT-mode\n", | ||
3875 | __func__, pt); | ||
3876 | /* clock delay */ | ||
3877 | HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt); | ||
3878 | a_st_wr_state = 1; /* G1 */ | ||
3879 | hc->hw.a_st_ctrl0[pt] = V_ST_MD; | ||
3880 | } else { | ||
3881 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3882 | printk(KERN_DEBUG | ||
3883 | "%s: ST port %d is TE-mode\n", | ||
3884 | __func__, pt); | ||
3885 | /* clock delay */ | ||
3886 | HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te); | ||
3887 | a_st_wr_state = 2; /* F2 */ | ||
3888 | hc->hw.a_st_ctrl0[pt] = 0; | ||
3889 | } | ||
3890 | if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) | ||
3891 | hc->hw.a_st_ctrl0[pt] |= V_TX_LI; | ||
3892 | /* line setup */ | ||
3893 | HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); | ||
3894 | /* disable E-channel */ | ||
3895 | if ((dch->dev.D.protocol == ISDN_P_NT_S0) || | ||
3896 | test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg)) | ||
3897 | HFC_outb(hc, A_ST_CTRL1, V_E_IGNO); | ||
3898 | else | ||
3899 | HFC_outb(hc, A_ST_CTRL1, 0); | ||
3900 | /* enable B-channel receive */ | ||
3901 | HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN); | ||
3902 | /* state machine setup */ | ||
3903 | HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA); | ||
3904 | udelay(6); /* wait at least 5,21us */ | ||
3905 | HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state); | ||
3906 | hc->hw.r_sci_msk |= 1 << pt; | ||
3907 | /* state machine interrupts */ | ||
3908 | HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk); | ||
3909 | /* unset sync on port */ | ||
3910 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
3911 | hc->syncronized &= | ||
3912 | ~(1 << hc->chan[dch->slot].port); | ||
3913 | plxsd_checksync(hc, 0); | ||
3914 | } | ||
3915 | } | ||
3916 | if (debug & DEBUG_HFCMULTI_INIT) | ||
3917 | printk("%s: done\n", __func__); | ||
3918 | } | ||
3919 | |||
3920 | |||
3921 | static int | ||
3922 | open_dchannel(struct hfc_multi *hc, struct dchannel *dch, | ||
3923 | struct channel_req *rq) | ||
3924 | { | ||
3925 | int err = 0; | ||
3926 | u_long flags; | ||
3927 | |||
3928 | if (debug & DEBUG_HW_OPEN) | ||
3929 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
3930 | dch->dev.id, __builtin_return_address(0)); | ||
3931 | if (rq->protocol == ISDN_P_NONE) | ||
3932 | return -EINVAL; | ||
3933 | if ((dch->dev.D.protocol != ISDN_P_NONE) && | ||
3934 | (dch->dev.D.protocol != rq->protocol)) { | ||
3935 | if (debug & DEBUG_HFCMULTI_MODE) | ||
3936 | printk(KERN_WARNING "%s: change protocol %x to %x\n", | ||
3937 | __func__, dch->dev.D.protocol, rq->protocol); | ||
3938 | } | ||
3939 | if ((dch->dev.D.protocol == ISDN_P_TE_S0) | ||
3940 | && (rq->protocol != ISDN_P_TE_S0)) | ||
3941 | l1_event(dch->l1, CLOSE_CHANNEL); | ||
3942 | if (dch->dev.D.protocol != rq->protocol) { | ||
3943 | if (rq->protocol == ISDN_P_TE_S0) { | ||
3944 | err = create_l1(dch, hfcm_l1callback); | ||
3945 | if (err) | ||
3946 | return err; | ||
3947 | } | ||
3948 | dch->dev.D.protocol = rq->protocol; | ||
3949 | spin_lock_irqsave(&hc->lock, flags); | ||
3950 | hfcmulti_initmode(dch); | ||
3951 | spin_unlock_irqrestore(&hc->lock, flags); | ||
3952 | } | ||
3953 | |||
3954 | if (((rq->protocol == ISDN_P_NT_S0) && (dch->state == 3)) || | ||
3955 | ((rq->protocol == ISDN_P_TE_S0) && (dch->state == 7)) || | ||
3956 | ((rq->protocol == ISDN_P_NT_E1) && (dch->state == 1)) || | ||
3957 | ((rq->protocol == ISDN_P_TE_E1) && (dch->state == 1))) { | ||
3958 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
3959 | 0, NULL, GFP_KERNEL); | ||
3960 | } | ||
3961 | rq->ch = &dch->dev.D; | ||
3962 | if (!try_module_get(THIS_MODULE)) | ||
3963 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
3964 | return 0; | ||
3965 | } | ||
3966 | |||
3967 | static int | ||
3968 | open_bchannel(struct hfc_multi *hc, struct dchannel *dch, | ||
3969 | struct channel_req *rq) | ||
3970 | { | ||
3971 | struct bchannel *bch; | ||
3972 | int ch; | ||
3973 | |||
3974 | if (!test_bit(rq->adr.channel, &dch->dev.channelmap[0])) | ||
3975 | return -EINVAL; | ||
3976 | if (rq->protocol == ISDN_P_NONE) | ||
3977 | return -EINVAL; | ||
3978 | if (hc->type == 1) | ||
3979 | ch = rq->adr.channel; | ||
3980 | else | ||
3981 | ch = (rq->adr.channel - 1) + (dch->slot - 2); | ||
3982 | bch = hc->chan[ch].bch; | ||
3983 | if (!bch) { | ||
3984 | printk(KERN_ERR "%s:internal error ch %d has no bch\n", | ||
3985 | __func__, ch); | ||
3986 | return -EINVAL; | ||
3987 | } | ||
3988 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
3989 | return -EBUSY; /* b-channel can be only open once */ | ||
3990 | bch->ch.protocol = rq->protocol; | ||
3991 | hc->chan[ch].rx_off = 0; | ||
3992 | rq->ch = &bch->ch; | ||
3993 | if (!try_module_get(THIS_MODULE)) | ||
3994 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
3995 | return 0; | ||
3996 | } | ||
3997 | |||
3998 | /* | ||
3999 | * device control function | ||
4000 | */ | ||
4001 | static int | ||
4002 | channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) | ||
4003 | { | ||
4004 | int ret = 0; | ||
4005 | |||
4006 | switch (cq->op) { | ||
4007 | case MISDN_CTRL_GETOP: | ||
4008 | cq->op = 0; | ||
4009 | break; | ||
4010 | default: | ||
4011 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
4012 | __func__, cq->op); | ||
4013 | ret = -EINVAL; | ||
4014 | break; | ||
4015 | } | ||
4016 | return ret; | ||
4017 | } | ||
4018 | |||
4019 | static int | ||
4020 | hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
4021 | { | ||
4022 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
4023 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
4024 | struct hfc_multi *hc = dch->hw; | ||
4025 | struct channel_req *rq; | ||
4026 | int err = 0; | ||
4027 | u_long flags; | ||
4028 | |||
4029 | if (dch->debug & DEBUG_HW) | ||
4030 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
4031 | __func__, cmd, arg); | ||
4032 | switch (cmd) { | ||
4033 | case OPEN_CHANNEL: | ||
4034 | rq = arg; | ||
4035 | switch (rq->protocol) { | ||
4036 | case ISDN_P_TE_S0: | ||
4037 | case ISDN_P_NT_S0: | ||
4038 | if (hc->type == 1) { | ||
4039 | err = -EINVAL; | ||
4040 | break; | ||
4041 | } | ||
4042 | err = open_dchannel(hc, dch, rq); /* locked there */ | ||
4043 | break; | ||
4044 | case ISDN_P_TE_E1: | ||
4045 | case ISDN_P_NT_E1: | ||
4046 | if (hc->type != 1) { | ||
4047 | err = -EINVAL; | ||
4048 | break; | ||
4049 | } | ||
4050 | err = open_dchannel(hc, dch, rq); /* locked there */ | ||
4051 | break; | ||
4052 | default: | ||
4053 | spin_lock_irqsave(&hc->lock, flags); | ||
4054 | err = open_bchannel(hc, dch, rq); | ||
4055 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4056 | } | ||
4057 | break; | ||
4058 | case CLOSE_CHANNEL: | ||
4059 | if (debug & DEBUG_HW_OPEN) | ||
4060 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
4061 | __func__, dch->dev.id, | ||
4062 | __builtin_return_address(0)); | ||
4063 | module_put(THIS_MODULE); | ||
4064 | break; | ||
4065 | case CONTROL_CHANNEL: | ||
4066 | spin_lock_irqsave(&hc->lock, flags); | ||
4067 | err = channel_dctrl(dch, arg); | ||
4068 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4069 | break; | ||
4070 | default: | ||
4071 | if (dch->debug & DEBUG_HW) | ||
4072 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
4073 | __func__, cmd); | ||
4074 | err = -EINVAL; | ||
4075 | } | ||
4076 | return err; | ||
4077 | } | ||
4078 | |||
4079 | /* | ||
4080 | * initialize the card | ||
4081 | */ | ||
4082 | |||
4083 | /* | ||
4084 | * start timer irq, wait some time and check if we have interrupts. | ||
4085 | * if not, reset chip and try again. | ||
4086 | */ | ||
4087 | static int | ||
4088 | init_card(struct hfc_multi *hc) | ||
4089 | { | ||
4090 | int err = -EIO; | ||
4091 | u_long flags; | ||
4092 | u_short *plx_acc; | ||
4093 | u_long plx_flags; | ||
4094 | |||
4095 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4096 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
4097 | |||
4098 | spin_lock_irqsave(&hc->lock, flags); | ||
4099 | /* set interrupts but leave global interrupt disabled */ | ||
4100 | hc->hw.r_irq_ctrl = V_FIFO_IRQ; | ||
4101 | disable_hwirq(hc); | ||
4102 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4103 | |||
4104 | if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, IRQF_SHARED, | ||
4105 | "HFC-multi", hc)) { | ||
4106 | printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", | ||
4107 | hc->pci_dev->irq); | ||
4108 | return -EIO; | ||
4109 | } | ||
4110 | hc->irq = hc->pci_dev->irq; | ||
4111 | |||
4112 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
4113 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
4114 | plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); | ||
4115 | writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), | ||
4116 | plx_acc); /* enable PCI & LINT1 irq */ | ||
4117 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
4118 | } | ||
4119 | |||
4120 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4121 | printk(KERN_DEBUG "%s: IRQ %d count %d\n", | ||
4122 | __func__, hc->irq, hc->irqcnt); | ||
4123 | err = init_chip(hc); | ||
4124 | if (err) | ||
4125 | goto error; | ||
4126 | /* | ||
4127 | * Finally enable IRQ output | ||
4128 | * this is only allowed, if an IRQ routine is allready | ||
4129 | * established for this HFC, so don't do that earlier | ||
4130 | */ | ||
4131 | spin_lock_irqsave(&hc->lock, flags); | ||
4132 | enable_hwirq(hc); | ||
4133 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4134 | /* printk(KERN_DEBUG "no master irq set!!!\n"); */ | ||
4135 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
4136 | schedule_timeout((100*HZ)/1000); /* Timeout 100ms */ | ||
4137 | /* turn IRQ off until chip is completely initialized */ | ||
4138 | spin_lock_irqsave(&hc->lock, flags); | ||
4139 | disable_hwirq(hc); | ||
4140 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4141 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4142 | printk(KERN_DEBUG "%s: IRQ %d count %d\n", | ||
4143 | __func__, hc->irq, hc->irqcnt); | ||
4144 | if (hc->irqcnt) { | ||
4145 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4146 | printk(KERN_DEBUG "%s: done\n", __func__); | ||
4147 | |||
4148 | return 0; | ||
4149 | } | ||
4150 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
4151 | printk(KERN_INFO "ignoring missing interrupts\n"); | ||
4152 | return 0; | ||
4153 | } | ||
4154 | |||
4155 | printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n", | ||
4156 | hc->irq); | ||
4157 | |||
4158 | err = -EIO; | ||
4159 | |||
4160 | error: | ||
4161 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
4162 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
4163 | plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); | ||
4164 | writew(0x00, plx_acc); /*disable IRQs*/ | ||
4165 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
4166 | } | ||
4167 | |||
4168 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4169 | printk(KERN_WARNING "%s: free irq %d\n", __func__, hc->irq); | ||
4170 | if (hc->irq) { | ||
4171 | free_irq(hc->irq, hc); | ||
4172 | hc->irq = 0; | ||
4173 | } | ||
4174 | |||
4175 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4176 | printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err); | ||
4177 | return err; | ||
4178 | } | ||
4179 | |||
4180 | /* | ||
4181 | * find pci device and set it up | ||
4182 | */ | ||
4183 | |||
4184 | static int | ||
4185 | setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, | ||
4186 | const struct pci_device_id *ent) | ||
4187 | { | ||
4188 | struct hm_map *m = (struct hm_map *)ent->driver_data; | ||
4189 | |||
4190 | printk(KERN_INFO | ||
4191 | "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", | ||
4192 | m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); | ||
4193 | |||
4194 | hc->pci_dev = pdev; | ||
4195 | if (m->clock2) | ||
4196 | test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); | ||
4197 | |||
4198 | if (ent->device == 0xB410) { | ||
4199 | test_and_set_bit(HFC_CHIP_B410P, &hc->chip); | ||
4200 | test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); | ||
4201 | test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
4202 | hc->slots = 32; | ||
4203 | } | ||
4204 | |||
4205 | if (hc->pci_dev->irq <= 0) { | ||
4206 | printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); | ||
4207 | return -EIO; | ||
4208 | } | ||
4209 | if (pci_enable_device(hc->pci_dev)) { | ||
4210 | printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); | ||
4211 | return -EIO; | ||
4212 | } | ||
4213 | hc->leds = m->leds; | ||
4214 | hc->ledstate = 0xAFFEAFFE; | ||
4215 | hc->opticalsupport = m->opticalsupport; | ||
4216 | |||
4217 | /* set memory access methods */ | ||
4218 | if (m->io_mode) /* use mode from card config */ | ||
4219 | hc->io_mode = m->io_mode; | ||
4220 | switch (hc->io_mode) { | ||
4221 | case HFC_IO_MODE_PLXSD: | ||
4222 | test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); | ||
4223 | hc->slots = 128; /* required */ | ||
4224 | /* fall through */ | ||
4225 | case HFC_IO_MODE_PCIMEM: | ||
4226 | hc->HFC_outb = HFC_outb_pcimem; | ||
4227 | hc->HFC_inb = HFC_inb_pcimem; | ||
4228 | hc->HFC_inw = HFC_inw_pcimem; | ||
4229 | hc->HFC_wait = HFC_wait_pcimem; | ||
4230 | hc->read_fifo = read_fifo_pcimem; | ||
4231 | hc->write_fifo = write_fifo_pcimem; | ||
4232 | break; | ||
4233 | case HFC_IO_MODE_REGIO: | ||
4234 | hc->HFC_outb = HFC_outb_regio; | ||
4235 | hc->HFC_inb = HFC_inb_regio; | ||
4236 | hc->HFC_inw = HFC_inw_regio; | ||
4237 | hc->HFC_wait = HFC_wait_regio; | ||
4238 | hc->read_fifo = read_fifo_regio; | ||
4239 | hc->write_fifo = write_fifo_regio; | ||
4240 | break; | ||
4241 | default: | ||
4242 | printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); | ||
4243 | pci_disable_device(hc->pci_dev); | ||
4244 | return -EIO; | ||
4245 | } | ||
4246 | hc->HFC_outb_nodebug = hc->HFC_outb; | ||
4247 | hc->HFC_inb_nodebug = hc->HFC_inb; | ||
4248 | hc->HFC_inw_nodebug = hc->HFC_inw; | ||
4249 | hc->HFC_wait_nodebug = hc->HFC_wait; | ||
4250 | #ifdef HFC_REGISTER_DEBUG | ||
4251 | hc->HFC_outb = HFC_outb_debug; | ||
4252 | hc->HFC_inb = HFC_inb_debug; | ||
4253 | hc->HFC_inw = HFC_inw_debug; | ||
4254 | hc->HFC_wait = HFC_wait_debug; | ||
4255 | #endif | ||
4256 | hc->pci_iobase = 0; | ||
4257 | hc->pci_membase = NULL; | ||
4258 | hc->plx_membase = NULL; | ||
4259 | |||
4260 | switch (hc->io_mode) { | ||
4261 | case HFC_IO_MODE_PLXSD: | ||
4262 | hc->plx_origmembase = hc->pci_dev->resource[0].start; | ||
4263 | /* MEMBASE 1 is PLX PCI Bridge */ | ||
4264 | |||
4265 | if (!hc->plx_origmembase) { | ||
4266 | printk(KERN_WARNING | ||
4267 | "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); | ||
4268 | pci_disable_device(hc->pci_dev); | ||
4269 | return -EIO; | ||
4270 | } | ||
4271 | |||
4272 | hc->plx_membase = ioremap(hc->plx_origmembase, 0x80); | ||
4273 | if (!hc->plx_membase) { | ||
4274 | printk(KERN_WARNING | ||
4275 | "HFC-multi: failed to remap plx address space. " | ||
4276 | "(internal error)\n"); | ||
4277 | pci_disable_device(hc->pci_dev); | ||
4278 | return -EIO; | ||
4279 | } | ||
4280 | printk(KERN_INFO | ||
4281 | "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n", | ||
4282 | (u_long)hc->plx_membase, hc->plx_origmembase); | ||
4283 | |||
4284 | hc->pci_origmembase = hc->pci_dev->resource[2].start; | ||
4285 | /* MEMBASE 1 is PLX PCI Bridge */ | ||
4286 | if (!hc->pci_origmembase) { | ||
4287 | printk(KERN_WARNING | ||
4288 | "HFC-multi: No IO-Memory for PCI card found\n"); | ||
4289 | pci_disable_device(hc->pci_dev); | ||
4290 | return -EIO; | ||
4291 | } | ||
4292 | |||
4293 | hc->pci_membase = ioremap(hc->pci_origmembase, 0x400); | ||
4294 | if (!hc->pci_membase) { | ||
4295 | printk(KERN_WARNING "HFC-multi: failed to remap io " | ||
4296 | "address space. (internal error)\n"); | ||
4297 | pci_disable_device(hc->pci_dev); | ||
4298 | return -EIO; | ||
4299 | } | ||
4300 | |||
4301 | printk(KERN_INFO | ||
4302 | "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d " | ||
4303 | "leds-type %d\n", | ||
4304 | hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, | ||
4305 | hc->pci_dev->irq, HZ, hc->leds); | ||
4306 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
4307 | break; | ||
4308 | case HFC_IO_MODE_PCIMEM: | ||
4309 | hc->pci_origmembase = hc->pci_dev->resource[1].start; | ||
4310 | if (!hc->pci_origmembase) { | ||
4311 | printk(KERN_WARNING | ||
4312 | "HFC-multi: No IO-Memory for PCI card found\n"); | ||
4313 | pci_disable_device(hc->pci_dev); | ||
4314 | return -EIO; | ||
4315 | } | ||
4316 | |||
4317 | hc->pci_membase = ioremap(hc->pci_origmembase, 256); | ||
4318 | if (!hc->pci_membase) { | ||
4319 | printk(KERN_WARNING | ||
4320 | "HFC-multi: failed to remap io address space. " | ||
4321 | "(internal error)\n"); | ||
4322 | pci_disable_device(hc->pci_dev); | ||
4323 | return -EIO; | ||
4324 | } | ||
4325 | printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d " | ||
4326 | "HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, | ||
4327 | hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); | ||
4328 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
4329 | break; | ||
4330 | case HFC_IO_MODE_REGIO: | ||
4331 | hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; | ||
4332 | if (!hc->pci_iobase) { | ||
4333 | printk(KERN_WARNING | ||
4334 | "HFC-multi: No IO for PCI card found\n"); | ||
4335 | pci_disable_device(hc->pci_dev); | ||
4336 | return -EIO; | ||
4337 | } | ||
4338 | |||
4339 | if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { | ||
4340 | printk(KERN_WARNING "HFC-multi: failed to request " | ||
4341 | "address space at 0x%08lx (internal error)\n", | ||
4342 | hc->pci_iobase); | ||
4343 | pci_disable_device(hc->pci_dev); | ||
4344 | return -EIO; | ||
4345 | } | ||
4346 | |||
4347 | printk(KERN_INFO | ||
4348 | "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", | ||
4349 | m->vendor_name, m->card_name, (u_int) hc->pci_iobase, | ||
4350 | hc->pci_dev->irq, HZ, hc->leds); | ||
4351 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); | ||
4352 | break; | ||
4353 | default: | ||
4354 | printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); | ||
4355 | pci_disable_device(hc->pci_dev); | ||
4356 | return -EIO; | ||
4357 | } | ||
4358 | |||
4359 | pci_set_drvdata(hc->pci_dev, hc); | ||
4360 | |||
4361 | /* At this point the needed PCI config is done */ | ||
4362 | /* fifos are still not enabled */ | ||
4363 | return 0; | ||
4364 | } | ||
4365 | |||
4366 | |||
4367 | /* | ||
4368 | * remove port | ||
4369 | */ | ||
4370 | |||
4371 | static void | ||
4372 | release_port(struct hfc_multi *hc, struct dchannel *dch) | ||
4373 | { | ||
4374 | int pt, ci, i = 0; | ||
4375 | u_long flags; | ||
4376 | struct bchannel *pb; | ||
4377 | |||
4378 | ci = dch->slot; | ||
4379 | pt = hc->chan[ci].port; | ||
4380 | |||
4381 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4382 | printk(KERN_DEBUG "%s: entered for port %d\n", | ||
4383 | __func__, pt + 1); | ||
4384 | |||
4385 | if (pt >= hc->ports) { | ||
4386 | printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", | ||
4387 | __func__, pt + 1); | ||
4388 | return; | ||
4389 | } | ||
4390 | |||
4391 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4392 | printk(KERN_DEBUG "%s: releasing port=%d\n", | ||
4393 | __func__, pt + 1); | ||
4394 | |||
4395 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | ||
4396 | l1_event(dch->l1, CLOSE_CHANNEL); | ||
4397 | |||
4398 | hc->chan[ci].dch = NULL; | ||
4399 | |||
4400 | if (hc->created[pt]) { | ||
4401 | hc->created[pt] = 0; | ||
4402 | mISDN_unregister_device(&dch->dev); | ||
4403 | } | ||
4404 | |||
4405 | spin_lock_irqsave(&hc->lock, flags); | ||
4406 | |||
4407 | if (dch->timer.function) { | ||
4408 | del_timer(&dch->timer); | ||
4409 | dch->timer.function = NULL; | ||
4410 | } | ||
4411 | |||
4412 | if (hc->type == 1) { /* E1 */ | ||
4413 | /* remove sync */ | ||
4414 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
4415 | hc->syncronized = 0; | ||
4416 | plxsd_checksync(hc, 1); | ||
4417 | } | ||
4418 | /* free channels */ | ||
4419 | for (i = 0; i <= 31; i++) { | ||
4420 | if (hc->chan[i].bch) { | ||
4421 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4422 | printk(KERN_DEBUG | ||
4423 | "%s: free port %d channel %d\n", | ||
4424 | __func__, hc->chan[i].port+1, i); | ||
4425 | pb = hc->chan[i].bch; | ||
4426 | hc->chan[i].bch = NULL; | ||
4427 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4428 | mISDN_freebchannel(pb); | ||
4429 | kfree(pb); | ||
4430 | kfree(hc->chan[i].coeff); | ||
4431 | spin_lock_irqsave(&hc->lock, flags); | ||
4432 | } | ||
4433 | } | ||
4434 | } else { | ||
4435 | /* remove sync */ | ||
4436 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
4437 | hc->syncronized &= | ||
4438 | ~(1 << hc->chan[ci].port); | ||
4439 | plxsd_checksync(hc, 1); | ||
4440 | } | ||
4441 | /* free channels */ | ||
4442 | if (hc->chan[ci - 2].bch) { | ||
4443 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4444 | printk(KERN_DEBUG | ||
4445 | "%s: free port %d channel %d\n", | ||
4446 | __func__, hc->chan[ci - 2].port+1, | ||
4447 | ci - 2); | ||
4448 | pb = hc->chan[ci - 2].bch; | ||
4449 | hc->chan[ci - 2].bch = NULL; | ||
4450 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4451 | mISDN_freebchannel(pb); | ||
4452 | kfree(pb); | ||
4453 | kfree(hc->chan[ci - 2].coeff); | ||
4454 | spin_lock_irqsave(&hc->lock, flags); | ||
4455 | } | ||
4456 | if (hc->chan[ci - 1].bch) { | ||
4457 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4458 | printk(KERN_DEBUG | ||
4459 | "%s: free port %d channel %d\n", | ||
4460 | __func__, hc->chan[ci - 1].port+1, | ||
4461 | ci - 1); | ||
4462 | pb = hc->chan[ci - 1].bch; | ||
4463 | hc->chan[ci - 1].bch = NULL; | ||
4464 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4465 | mISDN_freebchannel(pb); | ||
4466 | kfree(pb); | ||
4467 | kfree(hc->chan[ci - 1].coeff); | ||
4468 | spin_lock_irqsave(&hc->lock, flags); | ||
4469 | } | ||
4470 | } | ||
4471 | |||
4472 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4473 | |||
4474 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4475 | printk(KERN_DEBUG "%s: free port %d channel D\n", __func__, pt); | ||
4476 | mISDN_freedchannel(dch); | ||
4477 | kfree(dch); | ||
4478 | |||
4479 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4480 | printk(KERN_DEBUG "%s: done!\n", __func__); | ||
4481 | } | ||
4482 | |||
4483 | static void | ||
4484 | release_card(struct hfc_multi *hc) | ||
4485 | { | ||
4486 | u_long flags; | ||
4487 | int ch; | ||
4488 | |||
4489 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4490 | printk(KERN_WARNING "%s: release card (%d) entered\n", | ||
4491 | __func__, hc->id); | ||
4492 | |||
4493 | spin_lock_irqsave(&hc->lock, flags); | ||
4494 | disable_hwirq(hc); | ||
4495 | spin_unlock_irqrestore(&hc->lock, flags); | ||
4496 | |||
4497 | udelay(1000); | ||
4498 | |||
4499 | /* dimm leds */ | ||
4500 | if (hc->leds) | ||
4501 | hfcmulti_leds(hc); | ||
4502 | |||
4503 | /* disable D-channels & B-channels */ | ||
4504 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4505 | printk(KERN_DEBUG "%s: disable all channels (d and b)\n", | ||
4506 | __func__); | ||
4507 | for (ch = 0; ch <= 31; ch++) { | ||
4508 | if (hc->chan[ch].dch) | ||
4509 | release_port(hc, hc->chan[ch].dch); | ||
4510 | } | ||
4511 | |||
4512 | /* release hardware & irq */ | ||
4513 | if (hc->irq) { | ||
4514 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4515 | printk(KERN_WARNING "%s: free irq %d\n", | ||
4516 | __func__, hc->irq); | ||
4517 | free_irq(hc->irq, hc); | ||
4518 | hc->irq = 0; | ||
4519 | |||
4520 | } | ||
4521 | release_io_hfcmulti(hc); | ||
4522 | |||
4523 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4524 | printk(KERN_WARNING "%s: remove instance from list\n", | ||
4525 | __func__); | ||
4526 | list_del(&hc->list); | ||
4527 | |||
4528 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4529 | printk(KERN_WARNING "%s: delete instance\n", __func__); | ||
4530 | if (hc == syncmaster) | ||
4531 | syncmaster = NULL; | ||
4532 | kfree(hc); | ||
4533 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4534 | printk(KERN_WARNING "%s: card successfully removed\n", | ||
4535 | __func__); | ||
4536 | } | ||
4537 | |||
4538 | static int | ||
4539 | init_e1_port(struct hfc_multi *hc, struct hm_map *m) | ||
4540 | { | ||
4541 | struct dchannel *dch; | ||
4542 | struct bchannel *bch; | ||
4543 | int ch, ret = 0; | ||
4544 | char name[MISDN_MAX_IDLEN]; | ||
4545 | |||
4546 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
4547 | if (!dch) | ||
4548 | return -ENOMEM; | ||
4549 | dch->debug = debug; | ||
4550 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); | ||
4551 | dch->hw = hc; | ||
4552 | dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); | ||
4553 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
4554 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
4555 | dch->dev.D.send = handle_dmsg; | ||
4556 | dch->dev.D.ctrl = hfcm_dctrl; | ||
4557 | dch->dev.nrbchan = (hc->dslot)?30:31; | ||
4558 | dch->slot = hc->dslot; | ||
4559 | hc->chan[hc->dslot].dch = dch; | ||
4560 | hc->chan[hc->dslot].port = 0; | ||
4561 | hc->chan[hc->dslot].nt_timer = -1; | ||
4562 | for (ch = 1; ch <= 31; ch++) { | ||
4563 | if (ch == hc->dslot) /* skip dchannel */ | ||
4564 | continue; | ||
4565 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
4566 | if (!bch) { | ||
4567 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
4568 | __func__); | ||
4569 | ret = -ENOMEM; | ||
4570 | goto free_chan; | ||
4571 | } | ||
4572 | hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); | ||
4573 | if (!hc->chan[ch].coeff) { | ||
4574 | printk(KERN_ERR "%s: no memory for coeffs\n", | ||
4575 | __func__); | ||
4576 | ret = -ENOMEM; | ||
4577 | goto free_chan; | ||
4578 | } | ||
4579 | bch->nr = ch; | ||
4580 | bch->slot = ch; | ||
4581 | bch->debug = debug; | ||
4582 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
4583 | bch->hw = hc; | ||
4584 | bch->ch.send = handle_bmsg; | ||
4585 | bch->ch.ctrl = hfcm_bctrl; | ||
4586 | bch->ch.nr = ch; | ||
4587 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
4588 | hc->chan[ch].bch = bch; | ||
4589 | hc->chan[ch].port = 0; | ||
4590 | test_and_set_bit(bch->nr, &dch->dev.channelmap[0]); | ||
4591 | } | ||
4592 | /* set optical line type */ | ||
4593 | if (port[Port_cnt] & 0x001) { | ||
4594 | if (!m->opticalsupport) { | ||
4595 | printk(KERN_INFO | ||
4596 | "This board has no optical " | ||
4597 | "support\n"); | ||
4598 | } else { | ||
4599 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4600 | printk(KERN_DEBUG | ||
4601 | "%s: PORT set optical " | ||
4602 | "interfacs: card(%d) " | ||
4603 | "port(%d)\n", | ||
4604 | __func__, | ||
4605 | HFC_cnt + 1, 1); | ||
4606 | test_and_set_bit(HFC_CFG_OPTICAL, | ||
4607 | &hc->chan[hc->dslot].cfg); | ||
4608 | } | ||
4609 | } | ||
4610 | /* set LOS report */ | ||
4611 | if (port[Port_cnt] & 0x004) { | ||
4612 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4613 | printk(KERN_DEBUG "%s: PORT set " | ||
4614 | "LOS report: card(%d) port(%d)\n", | ||
4615 | __func__, HFC_cnt + 1, 1); | ||
4616 | test_and_set_bit(HFC_CFG_REPORT_LOS, | ||
4617 | &hc->chan[hc->dslot].cfg); | ||
4618 | } | ||
4619 | /* set AIS report */ | ||
4620 | if (port[Port_cnt] & 0x008) { | ||
4621 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4622 | printk(KERN_DEBUG "%s: PORT set " | ||
4623 | "AIS report: card(%d) port(%d)\n", | ||
4624 | __func__, HFC_cnt + 1, 1); | ||
4625 | test_and_set_bit(HFC_CFG_REPORT_AIS, | ||
4626 | &hc->chan[hc->dslot].cfg); | ||
4627 | } | ||
4628 | /* set SLIP report */ | ||
4629 | if (port[Port_cnt] & 0x010) { | ||
4630 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4631 | printk(KERN_DEBUG | ||
4632 | "%s: PORT set SLIP report: " | ||
4633 | "card(%d) port(%d)\n", | ||
4634 | __func__, HFC_cnt + 1, 1); | ||
4635 | test_and_set_bit(HFC_CFG_REPORT_SLIP, | ||
4636 | &hc->chan[hc->dslot].cfg); | ||
4637 | } | ||
4638 | /* set RDI report */ | ||
4639 | if (port[Port_cnt] & 0x020) { | ||
4640 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4641 | printk(KERN_DEBUG | ||
4642 | "%s: PORT set RDI report: " | ||
4643 | "card(%d) port(%d)\n", | ||
4644 | __func__, HFC_cnt + 1, 1); | ||
4645 | test_and_set_bit(HFC_CFG_REPORT_RDI, | ||
4646 | &hc->chan[hc->dslot].cfg); | ||
4647 | } | ||
4648 | /* set CRC-4 Mode */ | ||
4649 | if (!(port[Port_cnt] & 0x100)) { | ||
4650 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4651 | printk(KERN_DEBUG "%s: PORT turn on CRC4 report:" | ||
4652 | " card(%d) port(%d)\n", | ||
4653 | __func__, HFC_cnt + 1, 1); | ||
4654 | test_and_set_bit(HFC_CFG_CRC4, | ||
4655 | &hc->chan[hc->dslot].cfg); | ||
4656 | } else { | ||
4657 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4658 | printk(KERN_DEBUG "%s: PORT turn off CRC4" | ||
4659 | " report: card(%d) port(%d)\n", | ||
4660 | __func__, HFC_cnt + 1, 1); | ||
4661 | } | ||
4662 | /* set forced clock */ | ||
4663 | if (port[Port_cnt] & 0x0200) { | ||
4664 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4665 | printk(KERN_DEBUG "%s: PORT force getting clock from " | ||
4666 | "E1: card(%d) port(%d)\n", | ||
4667 | __func__, HFC_cnt + 1, 1); | ||
4668 | test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip); | ||
4669 | } else | ||
4670 | if (port[Port_cnt] & 0x0400) { | ||
4671 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4672 | printk(KERN_DEBUG "%s: PORT force putting clock to " | ||
4673 | "E1: card(%d) port(%d)\n", | ||
4674 | __func__, HFC_cnt + 1, 1); | ||
4675 | test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip); | ||
4676 | } | ||
4677 | /* set JATT PLL */ | ||
4678 | if (port[Port_cnt] & 0x0800) { | ||
4679 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4680 | printk(KERN_DEBUG "%s: PORT disable JATT PLL on " | ||
4681 | "E1: card(%d) port(%d)\n", | ||
4682 | __func__, HFC_cnt + 1, 1); | ||
4683 | test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); | ||
4684 | } | ||
4685 | /* set elastic jitter buffer */ | ||
4686 | if (port[Port_cnt] & 0x3000) { | ||
4687 | hc->chan[hc->dslot].jitter = (port[Port_cnt]>>12) & 0x3; | ||
4688 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4689 | printk(KERN_DEBUG | ||
4690 | "%s: PORT set elastic " | ||
4691 | "buffer to %d: card(%d) port(%d)\n", | ||
4692 | __func__, hc->chan[hc->dslot].jitter, | ||
4693 | HFC_cnt + 1, 1); | ||
4694 | } else | ||
4695 | hc->chan[hc->dslot].jitter = 2; /* default */ | ||
4696 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); | ||
4697 | ret = mISDN_register_device(&dch->dev, name); | ||
4698 | if (ret) | ||
4699 | goto free_chan; | ||
4700 | hc->created[0] = 1; | ||
4701 | return ret; | ||
4702 | free_chan: | ||
4703 | release_port(hc, dch); | ||
4704 | return ret; | ||
4705 | } | ||
4706 | |||
4707 | static int | ||
4708 | init_multi_port(struct hfc_multi *hc, int pt) | ||
4709 | { | ||
4710 | struct dchannel *dch; | ||
4711 | struct bchannel *bch; | ||
4712 | int ch, i, ret = 0; | ||
4713 | char name[MISDN_MAX_IDLEN]; | ||
4714 | |||
4715 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
4716 | if (!dch) | ||
4717 | return -ENOMEM; | ||
4718 | dch->debug = debug; | ||
4719 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); | ||
4720 | dch->hw = hc; | ||
4721 | dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
4722 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
4723 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
4724 | dch->dev.D.send = handle_dmsg; | ||
4725 | dch->dev.D.ctrl = hfcm_dctrl; | ||
4726 | dch->dev.nrbchan = 2; | ||
4727 | i = pt << 2; | ||
4728 | dch->slot = i + 2; | ||
4729 | hc->chan[i + 2].dch = dch; | ||
4730 | hc->chan[i + 2].port = pt; | ||
4731 | hc->chan[i + 2].nt_timer = -1; | ||
4732 | for (ch = 0; ch < dch->dev.nrbchan; ch++) { | ||
4733 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
4734 | if (!bch) { | ||
4735 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
4736 | __func__); | ||
4737 | ret = -ENOMEM; | ||
4738 | goto free_chan; | ||
4739 | } | ||
4740 | hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL); | ||
4741 | if (!hc->chan[i + ch].coeff) { | ||
4742 | printk(KERN_ERR "%s: no memory for coeffs\n", | ||
4743 | __func__); | ||
4744 | ret = -ENOMEM; | ||
4745 | goto free_chan; | ||
4746 | } | ||
4747 | bch->nr = ch + 1; | ||
4748 | bch->slot = i + ch; | ||
4749 | bch->debug = debug; | ||
4750 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
4751 | bch->hw = hc; | ||
4752 | bch->ch.send = handle_bmsg; | ||
4753 | bch->ch.ctrl = hfcm_bctrl; | ||
4754 | bch->ch.nr = ch + 1; | ||
4755 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
4756 | hc->chan[i + ch].bch = bch; | ||
4757 | hc->chan[i + ch].port = pt; | ||
4758 | test_and_set_bit(bch->nr, &dch->dev.channelmap[0]); | ||
4759 | } | ||
4760 | /* set master clock */ | ||
4761 | if (port[Port_cnt] & 0x001) { | ||
4762 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4763 | printk(KERN_DEBUG | ||
4764 | "%s: PROTOCOL set master clock: " | ||
4765 | "card(%d) port(%d)\n", | ||
4766 | __func__, HFC_cnt + 1, pt + 1); | ||
4767 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | ||
4768 | printk(KERN_ERR "Error: Master clock " | ||
4769 | "for port(%d) of card(%d) is only" | ||
4770 | " possible with TE-mode\n", | ||
4771 | pt + 1, HFC_cnt + 1); | ||
4772 | ret = -EINVAL; | ||
4773 | goto free_chan; | ||
4774 | } | ||
4775 | if (hc->masterclk >= 0) { | ||
4776 | printk(KERN_ERR "Error: Master clock " | ||
4777 | "for port(%d) of card(%d) already " | ||
4778 | "defined for port(%d)\n", | ||
4779 | pt + 1, HFC_cnt + 1, hc->masterclk+1); | ||
4780 | ret = -EINVAL; | ||
4781 | goto free_chan; | ||
4782 | } | ||
4783 | hc->masterclk = pt; | ||
4784 | } | ||
4785 | /* set transmitter line to non capacitive */ | ||
4786 | if (port[Port_cnt] & 0x002) { | ||
4787 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4788 | printk(KERN_DEBUG | ||
4789 | "%s: PROTOCOL set non capacitive " | ||
4790 | "transmitter: card(%d) port(%d)\n", | ||
4791 | __func__, HFC_cnt + 1, pt + 1); | ||
4792 | test_and_set_bit(HFC_CFG_NONCAP_TX, | ||
4793 | &hc->chan[i + 2].cfg); | ||
4794 | } | ||
4795 | /* disable E-channel */ | ||
4796 | if (port[Port_cnt] & 0x004) { | ||
4797 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4798 | printk(KERN_DEBUG | ||
4799 | "%s: PROTOCOL disable E-channel: " | ||
4800 | "card(%d) port(%d)\n", | ||
4801 | __func__, HFC_cnt + 1, pt + 1); | ||
4802 | test_and_set_bit(HFC_CFG_DIS_ECHANNEL, | ||
4803 | &hc->chan[i + 2].cfg); | ||
4804 | } | ||
4805 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d/%d", | ||
4806 | hc->type, HFC_cnt + 1, pt + 1); | ||
4807 | ret = mISDN_register_device(&dch->dev, name); | ||
4808 | if (ret) | ||
4809 | goto free_chan; | ||
4810 | hc->created[pt] = 1; | ||
4811 | return ret; | ||
4812 | free_chan: | ||
4813 | release_port(hc, dch); | ||
4814 | return ret; | ||
4815 | } | ||
4816 | |||
4817 | static int | ||
4818 | hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
4819 | { | ||
4820 | struct hm_map *m = (struct hm_map *)ent->driver_data; | ||
4821 | int ret_err = 0; | ||
4822 | int pt; | ||
4823 | struct hfc_multi *hc; | ||
4824 | u_long flags; | ||
4825 | u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ | ||
4826 | |||
4827 | if (HFC_cnt >= MAX_CARDS) { | ||
4828 | printk(KERN_ERR "too many cards (max=%d).\n", | ||
4829 | MAX_CARDS); | ||
4830 | return -EINVAL; | ||
4831 | } | ||
4832 | if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) { | ||
4833 | printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but " | ||
4834 | "type[%d] %d was supplied as module parameter\n", | ||
4835 | m->vendor_name, m->card_name, m->type, HFC_cnt, | ||
4836 | type[HFC_cnt] & 0xff); | ||
4837 | printk(KERN_WARNING "HFC-MULTI: Load module without parameters " | ||
4838 | "first, to see cards and their types."); | ||
4839 | return -EINVAL; | ||
4840 | } | ||
4841 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4842 | printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n", | ||
4843 | __func__, m->vendor_name, m->card_name, m->type, | ||
4844 | type[HFC_cnt]); | ||
4845 | |||
4846 | /* allocate card+fifo structure */ | ||
4847 | hc = kzalloc(sizeof(struct hfc_multi), GFP_KERNEL); | ||
4848 | if (!hc) { | ||
4849 | printk(KERN_ERR "No kmem for HFC-Multi card\n"); | ||
4850 | return -ENOMEM; | ||
4851 | } | ||
4852 | spin_lock_init(&hc->lock); | ||
4853 | hc->mtyp = m; | ||
4854 | hc->type = m->type; | ||
4855 | hc->ports = m->ports; | ||
4856 | hc->id = HFC_cnt; | ||
4857 | hc->pcm = pcm[HFC_cnt]; | ||
4858 | hc->io_mode = iomode[HFC_cnt]; | ||
4859 | if (dslot[HFC_cnt] < 0) { | ||
4860 | hc->dslot = 0; | ||
4861 | printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " | ||
4862 | "31 B-channels\n"); | ||
4863 | } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32) { | ||
4864 | hc->dslot = dslot[HFC_cnt]; | ||
4865 | printk(KERN_INFO "HFC-E1 card has alternating D-channel on " | ||
4866 | "time slot %d\n", dslot[HFC_cnt]); | ||
4867 | } else | ||
4868 | hc->dslot = 16; | ||
4869 | |||
4870 | /* set chip specific features */ | ||
4871 | hc->masterclk = -1; | ||
4872 | if (type[HFC_cnt] & 0x100) { | ||
4873 | test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); | ||
4874 | silence = 0xff; /* ulaw silence */ | ||
4875 | } else | ||
4876 | silence = 0x2a; /* alaw silence */ | ||
4877 | if (!(type[HFC_cnt] & 0x200)) | ||
4878 | test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); | ||
4879 | |||
4880 | if (type[HFC_cnt] & 0x800) | ||
4881 | test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
4882 | if (type[HFC_cnt] & 0x1000) { | ||
4883 | test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); | ||
4884 | test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
4885 | } | ||
4886 | if (type[HFC_cnt] & 0x4000) | ||
4887 | test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); | ||
4888 | if (type[HFC_cnt] & 0x8000) | ||
4889 | test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); | ||
4890 | hc->slots = 32; | ||
4891 | if (type[HFC_cnt] & 0x10000) | ||
4892 | hc->slots = 64; | ||
4893 | if (type[HFC_cnt] & 0x20000) | ||
4894 | hc->slots = 128; | ||
4895 | if (type[HFC_cnt] & 0x80000) { | ||
4896 | test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip); | ||
4897 | hc->wdcount = 0; | ||
4898 | hc->wdbyte = V_GPIO_OUT2; | ||
4899 | printk(KERN_NOTICE "Watchdog enabled\n"); | ||
4900 | } | ||
4901 | |||
4902 | /* setup pci, hc->slots may change due to PLXSD */ | ||
4903 | ret_err = setup_pci(hc, pdev, ent); | ||
4904 | if (ret_err) { | ||
4905 | if (hc == syncmaster) | ||
4906 | syncmaster = NULL; | ||
4907 | kfree(hc); | ||
4908 | return ret_err; | ||
4909 | } | ||
4910 | |||
4911 | /* crate channels */ | ||
4912 | for (pt = 0; pt < hc->ports; pt++) { | ||
4913 | if (Port_cnt >= MAX_PORTS) { | ||
4914 | printk(KERN_ERR "too many ports (max=%d).\n", | ||
4915 | MAX_PORTS); | ||
4916 | ret_err = -EINVAL; | ||
4917 | goto free_card; | ||
4918 | } | ||
4919 | if (hc->type == 1) | ||
4920 | ret_err = init_e1_port(hc, m); | ||
4921 | else | ||
4922 | ret_err = init_multi_port(hc, pt); | ||
4923 | if (debug & DEBUG_HFCMULTI_INIT) | ||
4924 | printk(KERN_DEBUG | ||
4925 | "%s: Registering D-channel, card(%d) port(%d)" | ||
4926 | "result %d\n", | ||
4927 | __func__, HFC_cnt + 1, pt, ret_err); | ||
4928 | |||
4929 | if (ret_err) { | ||
4930 | while (pt) { /* release already registered ports */ | ||
4931 | pt--; | ||
4932 | release_port(hc, hc->chan[(pt << 2) + 2].dch); | ||
4933 | } | ||
4934 | goto free_card; | ||
4935 | } | ||
4936 | Port_cnt++; | ||
4937 | } | ||
4938 | |||
4939 | /* disp switches */ | ||
4940 | switch (m->dip_type) { | ||
4941 | case DIP_4S: | ||
4942 | /* | ||
4943 | * get DIP Setting for beroNet 1S/2S/4S cards | ||
4944 | * check if Port Jumper config matches | ||
4945 | * module param 'protocol' | ||
4946 | * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + | ||
4947 | * GPI 19/23 (R_GPI_IN2)) | ||
4948 | */ | ||
4949 | dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) | | ||
4950 | ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) | | ||
4951 | (~HFC_inb(hc, R_GPI_IN2) & 0x08); | ||
4952 | |||
4953 | /* Port mode (TE/NT) jumpers */ | ||
4954 | pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4) & 0xf); | ||
4955 | |||
4956 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | ||
4957 | pmj = ~pmj & 0xf; | ||
4958 | |||
4959 | printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n", | ||
4960 | m->vendor_name, m->card_name, dips, pmj); | ||
4961 | break; | ||
4962 | case DIP_8S: | ||
4963 | /* | ||
4964 | * get DIP Setting for beroNet 8S0+ cards | ||
4965 | * | ||
4966 | * enable PCI auxbridge function | ||
4967 | */ | ||
4968 | HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); | ||
4969 | /* prepare access to auxport */ | ||
4970 | outw(0x4000, hc->pci_iobase + 4); | ||
4971 | /* | ||
4972 | * some dummy reads are required to | ||
4973 | * read valid DIP switch data | ||
4974 | */ | ||
4975 | dips = inb(hc->pci_iobase); | ||
4976 | dips = inb(hc->pci_iobase); | ||
4977 | dips = inb(hc->pci_iobase); | ||
4978 | dips = ~inb(hc->pci_iobase) & 0x3F; | ||
4979 | outw(0x0, hc->pci_iobase + 4); | ||
4980 | /* disable PCI auxbridge function */ | ||
4981 | HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); | ||
4982 | printk(KERN_INFO "%s: %s DIPs(0x%x)\n", | ||
4983 | m->vendor_name, m->card_name, dips); | ||
4984 | break; | ||
4985 | case DIP_E1: | ||
4986 | /* | ||
4987 | * get DIP Setting for beroNet E1 cards | ||
4988 | * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0) | ||
4989 | */ | ||
4990 | dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0)>>4; | ||
4991 | printk(KERN_INFO "%s: %s DIPs(0x%x)\n", | ||
4992 | m->vendor_name, m->card_name, dips); | ||
4993 | break; | ||
4994 | } | ||
4995 | |||
4996 | /* add to list */ | ||
4997 | spin_lock_irqsave(&HFClock, flags); | ||
4998 | list_add_tail(&hc->list, &HFClist); | ||
4999 | spin_unlock_irqrestore(&HFClock, flags); | ||
5000 | |||
5001 | /* initialize hardware */ | ||
5002 | ret_err = init_card(hc); | ||
5003 | if (ret_err) { | ||
5004 | printk(KERN_ERR "init card returns %d\n", ret_err); | ||
5005 | release_card(hc); | ||
5006 | return ret_err; | ||
5007 | } | ||
5008 | |||
5009 | /* start IRQ and return */ | ||
5010 | spin_lock_irqsave(&hc->lock, flags); | ||
5011 | enable_hwirq(hc); | ||
5012 | spin_unlock_irqrestore(&hc->lock, flags); | ||
5013 | return 0; | ||
5014 | |||
5015 | free_card: | ||
5016 | release_io_hfcmulti(hc); | ||
5017 | if (hc == syncmaster) | ||
5018 | syncmaster = NULL; | ||
5019 | kfree(hc); | ||
5020 | return ret_err; | ||
5021 | } | ||
5022 | |||
5023 | static void __devexit hfc_remove_pci(struct pci_dev *pdev) | ||
5024 | { | ||
5025 | struct hfc_multi *card = pci_get_drvdata(pdev); | ||
5026 | u_long flags; | ||
5027 | |||
5028 | if (debug) | ||
5029 | printk(KERN_INFO "removing hfc_multi card vendor:%x " | ||
5030 | "device:%x subvendor:%x subdevice:%x\n", | ||
5031 | pdev->vendor, pdev->device, | ||
5032 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
5033 | |||
5034 | if (card) { | ||
5035 | spin_lock_irqsave(&HFClock, flags); | ||
5036 | release_card(card); | ||
5037 | spin_unlock_irqrestore(&HFClock, flags); | ||
5038 | } else { | ||
5039 | if (debug) | ||
5040 | printk(KERN_WARNING "%s: drvdata allready removed\n", | ||
5041 | __func__); | ||
5042 | } | ||
5043 | } | ||
5044 | |||
5045 | #define VENDOR_CCD "Cologne Chip AG" | ||
5046 | #define VENDOR_BN "beroNet GmbH" | ||
5047 | #define VENDOR_DIG "Digium Inc." | ||
5048 | #define VENDOR_JH "Junghanns.NET GmbH" | ||
5049 | #define VENDOR_PRIM "PrimuX" | ||
5050 | |||
5051 | static const struct hm_map hfcm_map[] = { | ||
5052 | /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0}, | ||
5053 | /*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S}, | ||
5054 | /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0}, | ||
5055 | /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0}, | ||
5056 | /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0}, | ||
5057 | /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0}, | ||
5058 | /*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, 0, 0}, | ||
5059 | /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0}, | ||
5060 | /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO}, | ||
5061 | /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0}, | ||
5062 | /*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0}, | ||
5063 | /*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0}, | ||
5064 | |||
5065 | /*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0}, | ||
5066 | /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, | ||
5067 | HFC_IO_MODE_REGIO}, | ||
5068 | /*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0}, | ||
5069 | /*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0}, | ||
5070 | |||
5071 | /*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0}, | ||
5072 | /*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, | ||
5073 | /*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, | ||
5074 | |||
5075 | /*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0}, | ||
5076 | /*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0}, | ||
5077 | /*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, | ||
5078 | /*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, | ||
5079 | |||
5080 | /*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0}, | ||
5081 | /*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0}, | ||
5082 | /*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0}, | ||
5083 | |||
5084 | /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, | ||
5085 | HFC_IO_MODE_PLXSD}, | ||
5086 | /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, | ||
5087 | HFC_IO_MODE_PLXSD}, | ||
5088 | /*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0}, | ||
5089 | /*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0}, | ||
5090 | /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0}, | ||
5091 | }; | ||
5092 | |||
5093 | #undef H | ||
5094 | #define H(x) ((unsigned long)&hfcm_map[x]) | ||
5095 | static struct pci_device_id hfmultipci_ids[] __devinitdata = { | ||
5096 | |||
5097 | /* Cards with HFC-4S Chip */ | ||
5098 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5099 | PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */ | ||
5100 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5101 | PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */ | ||
5102 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5103 | PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */ | ||
5104 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5105 | PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */ | ||
5106 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5107 | PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */ | ||
5108 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5109 | PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */ | ||
5110 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5111 | PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */ | ||
5112 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5113 | PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */ | ||
5114 | { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, | ||
5115 | PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)}, | ||
5116 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5117 | PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */ | ||
5118 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5119 | PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)}, | ||
5120 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5121 | PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */ | ||
5122 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5123 | PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */ | ||
5124 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
5125 | PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */ | ||
5126 | |||
5127 | /* Cards with HFC-8S Chip */ | ||
5128 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5129 | PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */ | ||
5130 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5131 | PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */ | ||
5132 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5133 | PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ | ||
5134 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5135 | PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, | ||
5136 | /* IOB8ST Recording */ | ||
5137 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5138 | PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ | ||
5139 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5140 | PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST */ | ||
5141 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5142 | PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ | ||
5143 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
5144 | PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ | ||
5145 | |||
5146 | |||
5147 | /* Cards with HFC-E1 Chip */ | ||
5148 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5149 | PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */ | ||
5150 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5151 | PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */ | ||
5152 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5153 | PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */ | ||
5154 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5155 | PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */ | ||
5156 | |||
5157 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5158 | PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */ | ||
5159 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5160 | PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */ | ||
5161 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
5162 | PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */ | ||
5163 | |||
5164 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, | ||
5165 | PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ | ||
5166 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, | ||
5167 | PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ | ||
5168 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID, | ||
5169 | 0, 0, 0}, | ||
5170 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID, | ||
5171 | 0, 0, 0}, | ||
5172 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_ANY_ID, PCI_ANY_ID, | ||
5173 | 0, 0, 0}, | ||
5174 | {0, } | ||
5175 | }; | ||
5176 | #undef H | ||
5177 | |||
5178 | MODULE_DEVICE_TABLE(pci, hfmultipci_ids); | ||
5179 | |||
5180 | static int | ||
5181 | hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
5182 | { | ||
5183 | struct hm_map *m = (struct hm_map *)ent->driver_data; | ||
5184 | int ret; | ||
5185 | |||
5186 | if (m == NULL) { | ||
5187 | if (ent->vendor == PCI_VENDOR_ID_CCD) | ||
5188 | if (ent->device == PCI_DEVICE_ID_CCD_HFC4S || | ||
5189 | ent->device == PCI_DEVICE_ID_CCD_HFC8S || | ||
5190 | ent->device == PCI_DEVICE_ID_CCD_HFCE1) | ||
5191 | printk(KERN_ERR | ||
5192 | "unknown HFC multiport controller " | ||
5193 | "(vendor:%x device:%x subvendor:%x " | ||
5194 | "subdevice:%x) Please contact the " | ||
5195 | "driver maintainer for support.\n", | ||
5196 | ent->vendor, ent->device, | ||
5197 | ent->subvendor, ent->subdevice); | ||
5198 | return -ENODEV; | ||
5199 | } | ||
5200 | ret = hfcmulti_init(pdev, ent); | ||
5201 | if (ret) | ||
5202 | return ret; | ||
5203 | HFC_cnt++; | ||
5204 | printk(KERN_INFO "%d devices registered\n", HFC_cnt); | ||
5205 | return 0; | ||
5206 | } | ||
5207 | |||
5208 | static struct pci_driver hfcmultipci_driver = { | ||
5209 | .name = "hfc_multi", | ||
5210 | .probe = hfcmulti_probe, | ||
5211 | .remove = __devexit_p(hfc_remove_pci), | ||
5212 | .id_table = hfmultipci_ids, | ||
5213 | }; | ||
5214 | |||
5215 | static void __exit | ||
5216 | HFCmulti_cleanup(void) | ||
5217 | { | ||
5218 | struct hfc_multi *card, *next; | ||
5219 | |||
5220 | /* unload interrupt function symbol */ | ||
5221 | if (hfc_interrupt) | ||
5222 | symbol_put(ztdummy_extern_interrupt); | ||
5223 | if (register_interrupt) | ||
5224 | symbol_put(ztdummy_register_interrupt); | ||
5225 | if (unregister_interrupt) { | ||
5226 | if (interrupt_registered) { | ||
5227 | interrupt_registered = 0; | ||
5228 | unregister_interrupt(); | ||
5229 | } | ||
5230 | symbol_put(ztdummy_unregister_interrupt); | ||
5231 | } | ||
5232 | |||
5233 | list_for_each_entry_safe(card, next, &HFClist, list) | ||
5234 | release_card(card); | ||
5235 | /* get rid of all devices of this driver */ | ||
5236 | pci_unregister_driver(&hfcmultipci_driver); | ||
5237 | } | ||
5238 | |||
5239 | static int __init | ||
5240 | HFCmulti_init(void) | ||
5241 | { | ||
5242 | int err; | ||
5243 | |||
5244 | #ifdef IRQ_DEBUG | ||
5245 | printk(KERN_ERR "%s: IRQ_DEBUG IS ENABLED!\n", __func__); | ||
5246 | #endif | ||
5247 | |||
5248 | spin_lock_init(&HFClock); | ||
5249 | spin_lock_init(&plx_lock); | ||
5250 | |||
5251 | if (debug & DEBUG_HFCMULTI_INIT) | ||
5252 | printk(KERN_DEBUG "%s: init entered\n", __func__); | ||
5253 | |||
5254 | #ifdef __BIG_ENDIAN | ||
5255 | #error "not running on big endian machines now" | ||
5256 | #endif | ||
5257 | hfc_interrupt = symbol_get(ztdummy_extern_interrupt); | ||
5258 | register_interrupt = symbol_get(ztdummy_register_interrupt); | ||
5259 | unregister_interrupt = symbol_get(ztdummy_unregister_interrupt); | ||
5260 | printk(KERN_INFO "mISDN: HFC-multi driver %s\n", | ||
5261 | hfcmulti_revision); | ||
5262 | |||
5263 | switch (poll) { | ||
5264 | case 0: | ||
5265 | poll_timer = 6; | ||
5266 | poll = 128; | ||
5267 | break; | ||
5268 | /* | ||
5269 | * wenn dieses break nochmal verschwindet, | ||
5270 | * gibt es heisse ohren :-) | ||
5271 | * "without the break you will get hot ears ???" | ||
5272 | */ | ||
5273 | case 8: | ||
5274 | poll_timer = 2; | ||
5275 | break; | ||
5276 | case 16: | ||
5277 | poll_timer = 3; | ||
5278 | break; | ||
5279 | case 32: | ||
5280 | poll_timer = 4; | ||
5281 | break; | ||
5282 | case 64: | ||
5283 | poll_timer = 5; | ||
5284 | break; | ||
5285 | case 128: | ||
5286 | poll_timer = 6; | ||
5287 | break; | ||
5288 | case 256: | ||
5289 | poll_timer = 7; | ||
5290 | break; | ||
5291 | default: | ||
5292 | printk(KERN_ERR | ||
5293 | "%s: Wrong poll value (%d).\n", __func__, poll); | ||
5294 | err = -EINVAL; | ||
5295 | return err; | ||
5296 | |||
5297 | } | ||
5298 | |||
5299 | err = pci_register_driver(&hfcmultipci_driver); | ||
5300 | if (err < 0) { | ||
5301 | printk(KERN_ERR "error registering pci driver: %x\n", err); | ||
5302 | if (hfc_interrupt) | ||
5303 | symbol_put(ztdummy_extern_interrupt); | ||
5304 | if (register_interrupt) | ||
5305 | symbol_put(ztdummy_register_interrupt); | ||
5306 | if (unregister_interrupt) { | ||
5307 | if (interrupt_registered) { | ||
5308 | interrupt_registered = 0; | ||
5309 | unregister_interrupt(); | ||
5310 | } | ||
5311 | symbol_put(ztdummy_unregister_interrupt); | ||
5312 | } | ||
5313 | return err; | ||
5314 | } | ||
5315 | return 0; | ||
5316 | } | ||
5317 | |||
5318 | |||
5319 | module_init(HFCmulti_init); | ||
5320 | module_exit(HFCmulti_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c new file mode 100644 index 000000000000..917968530e1e --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfcpci.c | |||
@@ -0,0 +1,2256 @@ | |||
1 | /* | ||
2 | * | ||
3 | * hfcpci.c low level driver for CCD's hfc-pci based cards | ||
4 | * | ||
5 | * Author Werner Cornelius (werner@isdn4linux.de) | ||
6 | * based on existing driver for CCD hfc ISA cards | ||
7 | * type approval valid for HFC-S PCI A based card | ||
8 | * | ||
9 | * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) | ||
10 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
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, or (at your option) | ||
15 | * 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 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/mISDNhw.h> | ||
32 | |||
33 | #include "hfc_pci.h" | ||
34 | |||
35 | static const char *hfcpci_revision = "2.0"; | ||
36 | |||
37 | #define MAX_CARDS 8 | ||
38 | static int HFC_cnt; | ||
39 | static uint debug; | ||
40 | |||
41 | MODULE_AUTHOR("Karsten Keil"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | module_param(debug, uint, 0); | ||
44 | |||
45 | static LIST_HEAD(HFClist); | ||
46 | DEFINE_RWLOCK(HFClock); | ||
47 | |||
48 | enum { | ||
49 | HFC_CCD_2BD0, | ||
50 | HFC_CCD_B000, | ||
51 | HFC_CCD_B006, | ||
52 | HFC_CCD_B007, | ||
53 | HFC_CCD_B008, | ||
54 | HFC_CCD_B009, | ||
55 | HFC_CCD_B00A, | ||
56 | HFC_CCD_B00B, | ||
57 | HFC_CCD_B00C, | ||
58 | HFC_CCD_B100, | ||
59 | HFC_CCD_B700, | ||
60 | HFC_CCD_B701, | ||
61 | HFC_ASUS_0675, | ||
62 | HFC_BERKOM_A1T, | ||
63 | HFC_BERKOM_TCONCEPT, | ||
64 | HFC_ANIGMA_MC145575, | ||
65 | HFC_ZOLTRIX_2BD0, | ||
66 | HFC_DIGI_DF_M_IOM2_E, | ||
67 | HFC_DIGI_DF_M_E, | ||
68 | HFC_DIGI_DF_M_IOM2_A, | ||
69 | HFC_DIGI_DF_M_A, | ||
70 | HFC_ABOCOM_2BD1, | ||
71 | HFC_SITECOM_DC105V2, | ||
72 | }; | ||
73 | |||
74 | struct hfcPCI_hw { | ||
75 | unsigned char cirm; | ||
76 | unsigned char ctmt; | ||
77 | unsigned char clkdel; | ||
78 | unsigned char states; | ||
79 | unsigned char conn; | ||
80 | unsigned char mst_m; | ||
81 | unsigned char int_m1; | ||
82 | unsigned char int_m2; | ||
83 | unsigned char sctrl; | ||
84 | unsigned char sctrl_r; | ||
85 | unsigned char sctrl_e; | ||
86 | unsigned char trm; | ||
87 | unsigned char fifo_en; | ||
88 | unsigned char bswapped; | ||
89 | unsigned char protocol; | ||
90 | int nt_timer; | ||
91 | unsigned char *pci_io; /* start of PCI IO memory */ | ||
92 | dma_addr_t dmahandle; | ||
93 | void *fifos; /* FIFO memory */ | ||
94 | int last_bfifo_cnt[2]; | ||
95 | /* marker saving last b-fifo frame count */ | ||
96 | struct timer_list timer; | ||
97 | }; | ||
98 | |||
99 | #define HFC_CFG_MASTER 1 | ||
100 | #define HFC_CFG_SLAVE 2 | ||
101 | #define HFC_CFG_PCM 3 | ||
102 | #define HFC_CFG_2HFC 4 | ||
103 | #define HFC_CFG_SLAVEHFC 5 | ||
104 | #define HFC_CFG_NEG_F0 6 | ||
105 | #define HFC_CFG_SW_DD_DU 7 | ||
106 | |||
107 | #define FLG_HFC_TIMER_T1 16 | ||
108 | #define FLG_HFC_TIMER_T3 17 | ||
109 | |||
110 | #define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */ | ||
111 | #define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */ | ||
112 | #define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ | ||
113 | #define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ | ||
114 | |||
115 | |||
116 | struct hfc_pci { | ||
117 | struct list_head list; | ||
118 | u_char subtype; | ||
119 | u_char chanlimit; | ||
120 | u_char initdone; | ||
121 | u_long cfg; | ||
122 | u_int irq; | ||
123 | u_int irqcnt; | ||
124 | struct pci_dev *pdev; | ||
125 | struct hfcPCI_hw hw; | ||
126 | spinlock_t lock; /* card lock */ | ||
127 | struct dchannel dch; | ||
128 | struct bchannel bch[2]; | ||
129 | }; | ||
130 | |||
131 | /* Interface functions */ | ||
132 | static void | ||
133 | enable_hwirq(struct hfc_pci *hc) | ||
134 | { | ||
135 | hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; | ||
136 | Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | disable_hwirq(struct hfc_pci *hc) | ||
141 | { | ||
142 | hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); | ||
143 | Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * free hardware resources used by driver | ||
148 | */ | ||
149 | static void | ||
150 | release_io_hfcpci(struct hfc_pci *hc) | ||
151 | { | ||
152 | /* disable memory mapped ports + busmaster */ | ||
153 | pci_write_config_word(hc->pdev, PCI_COMMAND, 0); | ||
154 | del_timer(&hc->hw.timer); | ||
155 | pci_free_consistent(hc->pdev, 0x8000, hc->hw.fifos, hc->hw.dmahandle); | ||
156 | iounmap((void *)hc->hw.pci_io); | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * set mode (NT or TE) | ||
161 | */ | ||
162 | static void | ||
163 | hfcpci_setmode(struct hfc_pci *hc) | ||
164 | { | ||
165 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
166 | hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ | ||
167 | hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */ | ||
168 | hc->hw.states = 1; /* G1 */ | ||
169 | } else { | ||
170 | hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */ | ||
171 | hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */ | ||
172 | hc->hw.states = 2; /* F2 */ | ||
173 | } | ||
174 | Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); | ||
175 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states); | ||
176 | udelay(10); | ||
177 | Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */ | ||
178 | Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * function called to reset the HFC PCI chip. A complete software reset of chip | ||
183 | * and fifos is done. | ||
184 | */ | ||
185 | static void | ||
186 | reset_hfcpci(struct hfc_pci *hc) | ||
187 | { | ||
188 | u_char val; | ||
189 | int cnt = 0; | ||
190 | |||
191 | printk(KERN_DEBUG "reset_hfcpci: entered\n"); | ||
192 | val = Read_hfc(hc, HFCPCI_CHIP_ID); | ||
193 | printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); | ||
194 | /* enable memory mapped ports, disable busmaster */ | ||
195 | pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
196 | disable_hwirq(hc); | ||
197 | /* enable memory ports + busmaster */ | ||
198 | pci_write_config_word(hc->pdev, PCI_COMMAND, | ||
199 | PCI_ENA_MEMIO + PCI_ENA_MASTER); | ||
200 | val = Read_hfc(hc, HFCPCI_STATUS); | ||
201 | printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); | ||
202 | hc->hw.cirm = HFCPCI_RESET; /* Reset On */ | ||
203 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
204 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
205 | mdelay(10); /* Timeout 10ms */ | ||
206 | hc->hw.cirm = 0; /* Reset Off */ | ||
207 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
208 | val = Read_hfc(hc, HFCPCI_STATUS); | ||
209 | printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val); | ||
210 | while (cnt < 50000) { /* max 50000 us */ | ||
211 | udelay(5); | ||
212 | cnt += 5; | ||
213 | val = Read_hfc(hc, HFCPCI_STATUS); | ||
214 | if (!(val & 2)) | ||
215 | break; | ||
216 | } | ||
217 | printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt); | ||
218 | |||
219 | hc->hw.fifo_en = 0x30; /* only D fifos enabled */ | ||
220 | |||
221 | hc->hw.bswapped = 0; /* no exchange */ | ||
222 | hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; | ||
223 | hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ | ||
224 | hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ | ||
225 | hc->hw.sctrl_r = 0; | ||
226 | hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */ | ||
227 | hc->hw.mst_m = 0; | ||
228 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
229 | hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */ | ||
230 | if (test_bit(HFC_CFG_NEG_F0, &hc->cfg)) | ||
231 | hc->hw.mst_m |= HFCPCI_F0_NEGATIV; | ||
232 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
233 | Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); | ||
234 | Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); | ||
235 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); | ||
236 | |||
237 | hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | | ||
238 | HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; | ||
239 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
240 | |||
241 | /* Clear already pending ints */ | ||
242 | if (Read_hfc(hc, HFCPCI_INT_S1)); | ||
243 | |||
244 | /* set NT/TE mode */ | ||
245 | hfcpci_setmode(hc); | ||
246 | |||
247 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
248 | Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); | ||
249 | |||
250 | /* | ||
251 | * Init GCI/IOM2 in master mode | ||
252 | * Slots 0 and 1 are set for B-chan 1 and 2 | ||
253 | * D- and monitor/CI channel are not enabled | ||
254 | * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC | ||
255 | * STIO2 is used as data input, B1+B2 from IOM->ST | ||
256 | * ST B-channel send disabled -> continous 1s | ||
257 | * The IOM slots are always enabled | ||
258 | */ | ||
259 | if (test_bit(HFC_CFG_PCM, &hc->cfg)) { | ||
260 | /* set data flow directions: connect B1,B2: HFC to/from PCM */ | ||
261 | hc->hw.conn = 0x09; | ||
262 | } else { | ||
263 | hc->hw.conn = 0x36; /* set data flow directions */ | ||
264 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { | ||
265 | Write_hfc(hc, HFCPCI_B1_SSL, 0xC0); | ||
266 | Write_hfc(hc, HFCPCI_B2_SSL, 0xC1); | ||
267 | Write_hfc(hc, HFCPCI_B1_RSL, 0xC0); | ||
268 | Write_hfc(hc, HFCPCI_B2_RSL, 0xC1); | ||
269 | } else { | ||
270 | Write_hfc(hc, HFCPCI_B1_SSL, 0x80); | ||
271 | Write_hfc(hc, HFCPCI_B2_SSL, 0x81); | ||
272 | Write_hfc(hc, HFCPCI_B1_RSL, 0x80); | ||
273 | Write_hfc(hc, HFCPCI_B2_RSL, 0x81); | ||
274 | } | ||
275 | } | ||
276 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
277 | val = Read_hfc(hc, HFCPCI_INT_S2); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Timer function called when kernel timer expires | ||
282 | */ | ||
283 | static void | ||
284 | hfcpci_Timer(struct hfc_pci *hc) | ||
285 | { | ||
286 | hc->hw.timer.expires = jiffies + 75; | ||
287 | /* WD RESET */ | ||
288 | /* | ||
289 | * WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80); | ||
290 | * add_timer(&hc->hw.timer); | ||
291 | */ | ||
292 | } | ||
293 | |||
294 | |||
295 | /* | ||
296 | * select a b-channel entry matching and active | ||
297 | */ | ||
298 | static struct bchannel * | ||
299 | Sel_BCS(struct hfc_pci *hc, int channel) | ||
300 | { | ||
301 | if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) && | ||
302 | (hc->bch[0].nr & channel)) | ||
303 | return &hc->bch[0]; | ||
304 | else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) && | ||
305 | (hc->bch[1].nr & channel)) | ||
306 | return &hc->bch[1]; | ||
307 | else | ||
308 | return NULL; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * clear the desired B-channel rx fifo | ||
313 | */ | ||
314 | static void | ||
315 | hfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo) | ||
316 | { | ||
317 | u_char fifo_state; | ||
318 | struct bzfifo *bzr; | ||
319 | |||
320 | if (fifo) { | ||
321 | bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; | ||
322 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX; | ||
323 | } else { | ||
324 | bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; | ||
325 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX; | ||
326 | } | ||
327 | if (fifo_state) | ||
328 | hc->hw.fifo_en ^= fifo_state; | ||
329 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
330 | hc->hw.last_bfifo_cnt[fifo] = 0; | ||
331 | bzr->f1 = MAX_B_FRAMES; | ||
332 | bzr->f2 = bzr->f1; /* init F pointers to remain constant */ | ||
333 | bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); | ||
334 | bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16( | ||
335 | le16_to_cpu(bzr->za[MAX_B_FRAMES].z1)); | ||
336 | if (fifo_state) | ||
337 | hc->hw.fifo_en |= fifo_state; | ||
338 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * clear the desired B-channel tx fifo | ||
343 | */ | ||
344 | static void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo) | ||
345 | { | ||
346 | u_char fifo_state; | ||
347 | struct bzfifo *bzt; | ||
348 | |||
349 | if (fifo) { | ||
350 | bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; | ||
351 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX; | ||
352 | } else { | ||
353 | bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; | ||
354 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX; | ||
355 | } | ||
356 | if (fifo_state) | ||
357 | hc->hw.fifo_en ^= fifo_state; | ||
358 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
359 | if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) | ||
360 | printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) " | ||
361 | "z1(%x) z2(%x) state(%x)\n", | ||
362 | fifo, bzt->f1, bzt->f2, | ||
363 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), | ||
364 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z2), | ||
365 | fifo_state); | ||
366 | bzt->f2 = MAX_B_FRAMES; | ||
367 | bzt->f1 = bzt->f2; /* init F pointers to remain constant */ | ||
368 | bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); | ||
369 | bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16( | ||
370 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z1 - 1)); | ||
371 | if (fifo_state) | ||
372 | hc->hw.fifo_en |= fifo_state; | ||
373 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
374 | if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) | ||
375 | printk(KERN_DEBUG | ||
376 | "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n", | ||
377 | fifo, bzt->f1, bzt->f2, | ||
378 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), | ||
379 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z2)); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * read a complete B-frame out of the buffer | ||
384 | */ | ||
385 | static void | ||
386 | hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, | ||
387 | u_char *bdata, int count) | ||
388 | { | ||
389 | u_char *ptr, *ptr1, new_f2; | ||
390 | int total, maxlen, new_z2; | ||
391 | struct zt *zp; | ||
392 | |||
393 | if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) | ||
394 | printk(KERN_DEBUG "hfcpci_empty_fifo\n"); | ||
395 | zp = &bz->za[bz->f2]; /* point to Z-Regs */ | ||
396 | new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */ | ||
397 | if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
398 | new_z2 -= B_FIFO_SIZE; /* buffer wrap */ | ||
399 | new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; | ||
400 | if ((count > MAX_DATA_SIZE + 3) || (count < 4) || | ||
401 | (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { | ||
402 | if (bch->debug & DEBUG_HW) | ||
403 | printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet " | ||
404 | "invalid length %d or crc\n", count); | ||
405 | #ifdef ERROR_STATISTIC | ||
406 | bch->err_inv++; | ||
407 | #endif | ||
408 | bz->za[new_f2].z2 = cpu_to_le16(new_z2); | ||
409 | bz->f2 = new_f2; /* next buffer */ | ||
410 | } else { | ||
411 | bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC); | ||
412 | if (!bch->rx_skb) { | ||
413 | printk(KERN_WARNING "HFCPCI: receive out of memory\n"); | ||
414 | return; | ||
415 | } | ||
416 | total = count; | ||
417 | count -= 3; | ||
418 | ptr = skb_put(bch->rx_skb, count); | ||
419 | |||
420 | if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) | ||
421 | maxlen = count; /* complete transfer */ | ||
422 | else | ||
423 | maxlen = B_FIFO_SIZE + B_SUB_VAL - | ||
424 | le16_to_cpu(zp->z2); /* maximum */ | ||
425 | |||
426 | ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); | ||
427 | /* start of data */ | ||
428 | memcpy(ptr, ptr1, maxlen); /* copy data */ | ||
429 | count -= maxlen; | ||
430 | |||
431 | if (count) { /* rest remaining */ | ||
432 | ptr += maxlen; | ||
433 | ptr1 = bdata; /* start of buffer */ | ||
434 | memcpy(ptr, ptr1, count); /* rest */ | ||
435 | } | ||
436 | bz->za[new_f2].z2 = cpu_to_le16(new_z2); | ||
437 | bz->f2 = new_f2; /* next buffer */ | ||
438 | recv_Bchannel(bch); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * D-channel receive procedure | ||
444 | */ | ||
445 | static int | ||
446 | receive_dmsg(struct hfc_pci *hc) | ||
447 | { | ||
448 | struct dchannel *dch = &hc->dch; | ||
449 | int maxlen; | ||
450 | int rcnt, total; | ||
451 | int count = 5; | ||
452 | u_char *ptr, *ptr1; | ||
453 | struct dfifo *df; | ||
454 | struct zt *zp; | ||
455 | |||
456 | df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx; | ||
457 | while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { | ||
458 | zp = &df->za[df->f2 & D_FREG_MASK]; | ||
459 | rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); | ||
460 | if (rcnt < 0) | ||
461 | rcnt += D_FIFO_SIZE; | ||
462 | rcnt++; | ||
463 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
464 | printk(KERN_DEBUG | ||
465 | "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n", | ||
466 | df->f1, df->f2, | ||
467 | le16_to_cpu(zp->z1), | ||
468 | le16_to_cpu(zp->z2), | ||
469 | rcnt); | ||
470 | |||
471 | if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || | ||
472 | (df->data[le16_to_cpu(zp->z1)])) { | ||
473 | if (dch->debug & DEBUG_HW) | ||
474 | printk(KERN_DEBUG | ||
475 | "empty_fifo hfcpci paket inv. len " | ||
476 | "%d or crc %d\n", | ||
477 | rcnt, | ||
478 | df->data[le16_to_cpu(zp->z1)]); | ||
479 | #ifdef ERROR_STATISTIC | ||
480 | cs->err_rx++; | ||
481 | #endif | ||
482 | df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | | ||
483 | (MAX_D_FRAMES + 1); /* next buffer */ | ||
484 | df->za[df->f2 & D_FREG_MASK].z2 = | ||
485 | cpu_to_le16((zp->z2 + rcnt) & (D_FIFO_SIZE - 1)); | ||
486 | } else { | ||
487 | dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); | ||
488 | if (!dch->rx_skb) { | ||
489 | printk(KERN_WARNING | ||
490 | "HFC-PCI: D receive out of memory\n"); | ||
491 | break; | ||
492 | } | ||
493 | total = rcnt; | ||
494 | rcnt -= 3; | ||
495 | ptr = skb_put(dch->rx_skb, rcnt); | ||
496 | |||
497 | if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE) | ||
498 | maxlen = rcnt; /* complete transfer */ | ||
499 | else | ||
500 | maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2); | ||
501 | /* maximum */ | ||
502 | |||
503 | ptr1 = df->data + le16_to_cpu(zp->z2); | ||
504 | /* start of data */ | ||
505 | memcpy(ptr, ptr1, maxlen); /* copy data */ | ||
506 | rcnt -= maxlen; | ||
507 | |||
508 | if (rcnt) { /* rest remaining */ | ||
509 | ptr += maxlen; | ||
510 | ptr1 = df->data; /* start of buffer */ | ||
511 | memcpy(ptr, ptr1, rcnt); /* rest */ | ||
512 | } | ||
513 | df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | | ||
514 | (MAX_D_FRAMES + 1); /* next buffer */ | ||
515 | df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16(( | ||
516 | le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); | ||
517 | recv_Dchannel(dch); | ||
518 | } | ||
519 | } | ||
520 | return 1; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * check for transparent receive data and read max one threshold size if avail | ||
525 | */ | ||
526 | int | ||
527 | hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) | ||
528 | { | ||
529 | unsigned short *z1r, *z2r; | ||
530 | int new_z2, fcnt, maxlen; | ||
531 | u_char *ptr, *ptr1; | ||
532 | |||
533 | z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ | ||
534 | z2r = z1r + 1; | ||
535 | |||
536 | fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); | ||
537 | if (!fcnt) | ||
538 | return 0; /* no data avail */ | ||
539 | |||
540 | if (fcnt <= 0) | ||
541 | fcnt += B_FIFO_SIZE; /* bytes actually buffered */ | ||
542 | if (fcnt > HFCPCI_BTRANS_THRESHOLD) | ||
543 | fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ | ||
544 | |||
545 | new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ | ||
546 | if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
547 | new_z2 -= B_FIFO_SIZE; /* buffer wrap */ | ||
548 | |||
549 | bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC); | ||
550 | if (bch->rx_skb) { | ||
551 | ptr = skb_put(bch->rx_skb, fcnt); | ||
552 | if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) | ||
553 | maxlen = fcnt; /* complete transfer */ | ||
554 | else | ||
555 | maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); | ||
556 | /* maximum */ | ||
557 | |||
558 | ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); | ||
559 | /* start of data */ | ||
560 | memcpy(ptr, ptr1, maxlen); /* copy data */ | ||
561 | fcnt -= maxlen; | ||
562 | |||
563 | if (fcnt) { /* rest remaining */ | ||
564 | ptr += maxlen; | ||
565 | ptr1 = bdata; /* start of buffer */ | ||
566 | memcpy(ptr, ptr1, fcnt); /* rest */ | ||
567 | } | ||
568 | recv_Bchannel(bch); | ||
569 | } else | ||
570 | printk(KERN_WARNING "HFCPCI: receive out of memory\n"); | ||
571 | |||
572 | *z2r = cpu_to_le16(new_z2); /* new position */ | ||
573 | return 1; | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * B-channel main receive routine | ||
578 | */ | ||
579 | void | ||
580 | main_rec_hfcpci(struct bchannel *bch) | ||
581 | { | ||
582 | struct hfc_pci *hc = bch->hw; | ||
583 | int rcnt, real_fifo; | ||
584 | int receive, count = 5; | ||
585 | struct bzfifo *bz; | ||
586 | u_char *bdata; | ||
587 | struct zt *zp; | ||
588 | |||
589 | |||
590 | if ((bch->nr & 2) && (!hc->hw.bswapped)) { | ||
591 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; | ||
592 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; | ||
593 | real_fifo = 1; | ||
594 | } else { | ||
595 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; | ||
596 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; | ||
597 | real_fifo = 0; | ||
598 | } | ||
599 | Begin: | ||
600 | count--; | ||
601 | if (bz->f1 != bz->f2) { | ||
602 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
603 | printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", | ||
604 | bch->nr, bz->f1, bz->f2); | ||
605 | zp = &bz->za[bz->f2]; | ||
606 | |||
607 | rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); | ||
608 | if (rcnt < 0) | ||
609 | rcnt += B_FIFO_SIZE; | ||
610 | rcnt++; | ||
611 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
612 | printk(KERN_DEBUG | ||
613 | "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", | ||
614 | bch->nr, le16_to_cpu(zp->z1), | ||
615 | le16_to_cpu(zp->z2), rcnt); | ||
616 | hfcpci_empty_bfifo(bch, bz, bdata, rcnt); | ||
617 | rcnt = bz->f1 - bz->f2; | ||
618 | if (rcnt < 0) | ||
619 | rcnt += MAX_B_FRAMES + 1; | ||
620 | if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { | ||
621 | rcnt = 0; | ||
622 | hfcpci_clear_fifo_rx(hc, real_fifo); | ||
623 | } | ||
624 | hc->hw.last_bfifo_cnt[real_fifo] = rcnt; | ||
625 | if (rcnt > 1) | ||
626 | receive = 1; | ||
627 | else | ||
628 | receive = 0; | ||
629 | } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
630 | receive = hfcpci_empty_fifo_trans(bch, bz, bdata); | ||
631 | else | ||
632 | receive = 0; | ||
633 | if (count && receive) | ||
634 | goto Begin; | ||
635 | |||
636 | } | ||
637 | |||
638 | /* | ||
639 | * D-channel send routine | ||
640 | */ | ||
641 | static void | ||
642 | hfcpci_fill_dfifo(struct hfc_pci *hc) | ||
643 | { | ||
644 | struct dchannel *dch = &hc->dch; | ||
645 | int fcnt; | ||
646 | int count, new_z1, maxlen; | ||
647 | struct dfifo *df; | ||
648 | u_char *src, *dst, new_f1; | ||
649 | |||
650 | if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO)) | ||
651 | printk(KERN_DEBUG "%s\n", __func__); | ||
652 | |||
653 | if (!dch->tx_skb) | ||
654 | return; | ||
655 | count = dch->tx_skb->len - dch->tx_idx; | ||
656 | if (count <= 0) | ||
657 | return; | ||
658 | df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx; | ||
659 | |||
660 | if (dch->debug & DEBUG_HW_DFIFO) | ||
661 | printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__, | ||
662 | df->f1, df->f2, | ||
663 | le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1)); | ||
664 | fcnt = df->f1 - df->f2; /* frame count actually buffered */ | ||
665 | if (fcnt < 0) | ||
666 | fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ | ||
667 | if (fcnt > (MAX_D_FRAMES - 1)) { | ||
668 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
669 | printk(KERN_DEBUG | ||
670 | "hfcpci_fill_Dfifo more as 14 frames\n"); | ||
671 | #ifdef ERROR_STATISTIC | ||
672 | cs->err_tx++; | ||
673 | #endif | ||
674 | return; | ||
675 | } | ||
676 | /* now determine free bytes in FIFO buffer */ | ||
677 | maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) - | ||
678 | le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1; | ||
679 | if (maxlen <= 0) | ||
680 | maxlen += D_FIFO_SIZE; /* count now contains available bytes */ | ||
681 | |||
682 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
683 | printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n", | ||
684 | count, maxlen); | ||
685 | if (count > maxlen) { | ||
686 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
687 | printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n"); | ||
688 | return; | ||
689 | } | ||
690 | new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & | ||
691 | (D_FIFO_SIZE - 1); | ||
692 | new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); | ||
693 | src = dch->tx_skb->data + dch->tx_idx; /* source pointer */ | ||
694 | dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); | ||
695 | maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); | ||
696 | /* end fifo */ | ||
697 | if (maxlen > count) | ||
698 | maxlen = count; /* limit size */ | ||
699 | memcpy(dst, src, maxlen); /* first copy */ | ||
700 | |||
701 | count -= maxlen; /* remaining bytes */ | ||
702 | if (count) { | ||
703 | dst = df->data; /* start of buffer */ | ||
704 | src += maxlen; /* new position */ | ||
705 | memcpy(dst, src, count); | ||
706 | } | ||
707 | df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); | ||
708 | /* for next buffer */ | ||
709 | df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); | ||
710 | /* new pos actual buffer */ | ||
711 | df->f1 = new_f1; /* next frame */ | ||
712 | dch->tx_idx = dch->tx_skb->len; | ||
713 | } | ||
714 | |||
715 | /* | ||
716 | * B-channel send routine | ||
717 | */ | ||
718 | static void | ||
719 | hfcpci_fill_fifo(struct bchannel *bch) | ||
720 | { | ||
721 | struct hfc_pci *hc = bch->hw; | ||
722 | int maxlen, fcnt; | ||
723 | int count, new_z1; | ||
724 | struct bzfifo *bz; | ||
725 | u_char *bdata; | ||
726 | u_char new_f1, *src, *dst; | ||
727 | unsigned short *z1t, *z2t; | ||
728 | |||
729 | if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) | ||
730 | printk(KERN_DEBUG "%s\n", __func__); | ||
731 | if ((!bch->tx_skb) || bch->tx_skb->len <= 0) | ||
732 | return; | ||
733 | count = bch->tx_skb->len - bch->tx_idx; | ||
734 | if ((bch->nr & 2) && (!hc->hw.bswapped)) { | ||
735 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; | ||
736 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; | ||
737 | } else { | ||
738 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; | ||
739 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1; | ||
740 | } | ||
741 | |||
742 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { | ||
743 | z1t = &bz->za[MAX_B_FRAMES].z1; | ||
744 | z2t = z1t + 1; | ||
745 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
746 | printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) " | ||
747 | "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count, | ||
748 | le16_to_cpu(*z1t), le16_to_cpu(*z2t)); | ||
749 | fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); | ||
750 | if (fcnt <= 0) | ||
751 | fcnt += B_FIFO_SIZE; | ||
752 | /* fcnt contains available bytes in fifo */ | ||
753 | fcnt = B_FIFO_SIZE - fcnt; | ||
754 | /* remaining bytes to send (bytes in fifo) */ | ||
755 | next_t_frame: | ||
756 | count = bch->tx_skb->len - bch->tx_idx; | ||
757 | /* maximum fill shall be HFCPCI_BTRANS_MAX */ | ||
758 | if (count > HFCPCI_BTRANS_MAX - fcnt) | ||
759 | count = HFCPCI_BTRANS_MAX - fcnt; | ||
760 | if (count <= 0) | ||
761 | return; | ||
762 | /* data is suitable for fifo */ | ||
763 | new_z1 = le16_to_cpu(*z1t) + count; | ||
764 | /* new buffer Position */ | ||
765 | if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
766 | new_z1 -= B_FIFO_SIZE; /* buffer wrap */ | ||
767 | src = bch->tx_skb->data + bch->tx_idx; | ||
768 | /* source pointer */ | ||
769 | dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); | ||
770 | maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); | ||
771 | /* end of fifo */ | ||
772 | if (bch->debug & DEBUG_HW_BFIFO) | ||
773 | printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) " | ||
774 | "maxl(%d) nz1(%x) dst(%p)\n", | ||
775 | fcnt, maxlen, new_z1, dst); | ||
776 | fcnt += count; | ||
777 | bch->tx_idx += count; | ||
778 | if (maxlen > count) | ||
779 | maxlen = count; /* limit size */ | ||
780 | memcpy(dst, src, maxlen); /* first copy */ | ||
781 | count -= maxlen; /* remaining bytes */ | ||
782 | if (count) { | ||
783 | dst = bdata; /* start of buffer */ | ||
784 | src += maxlen; /* new position */ | ||
785 | memcpy(dst, src, count); | ||
786 | } | ||
787 | *z1t = cpu_to_le16(new_z1); /* now send data */ | ||
788 | if (bch->tx_idx < bch->tx_skb->len) | ||
789 | return; | ||
790 | /* send confirm, on trans, free on hdlc. */ | ||
791 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
792 | confirm_Bsend(bch); | ||
793 | dev_kfree_skb(bch->tx_skb); | ||
794 | if (get_next_bframe(bch)) | ||
795 | goto next_t_frame; | ||
796 | return; | ||
797 | } | ||
798 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
799 | printk(KERN_DEBUG | ||
800 | "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n", | ||
801 | __func__, bch->nr, bz->f1, bz->f2, | ||
802 | bz->za[bz->f1].z1); | ||
803 | fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ | ||
804 | if (fcnt < 0) | ||
805 | fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ | ||
806 | if (fcnt > (MAX_B_FRAMES - 1)) { | ||
807 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
808 | printk(KERN_DEBUG | ||
809 | "hfcpci_fill_Bfifo more as 14 frames\n"); | ||
810 | return; | ||
811 | } | ||
812 | /* now determine free bytes in FIFO buffer */ | ||
813 | maxlen = le16_to_cpu(bz->za[bz->f2].z2) - | ||
814 | le16_to_cpu(bz->za[bz->f1].z1) - 1; | ||
815 | if (maxlen <= 0) | ||
816 | maxlen += B_FIFO_SIZE; /* count now contains available bytes */ | ||
817 | |||
818 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
819 | printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n", | ||
820 | bch->nr, count, maxlen); | ||
821 | |||
822 | if (maxlen < count) { | ||
823 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
824 | printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n"); | ||
825 | return; | ||
826 | } | ||
827 | new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count; | ||
828 | /* new buffer Position */ | ||
829 | if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
830 | new_z1 -= B_FIFO_SIZE; /* buffer wrap */ | ||
831 | |||
832 | new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); | ||
833 | src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ | ||
834 | dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); | ||
835 | maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); | ||
836 | /* end fifo */ | ||
837 | if (maxlen > count) | ||
838 | maxlen = count; /* limit size */ | ||
839 | memcpy(dst, src, maxlen); /* first copy */ | ||
840 | |||
841 | count -= maxlen; /* remaining bytes */ | ||
842 | if (count) { | ||
843 | dst = bdata; /* start of buffer */ | ||
844 | src += maxlen; /* new position */ | ||
845 | memcpy(dst, src, count); | ||
846 | } | ||
847 | bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ | ||
848 | bz->f1 = new_f1; /* next frame */ | ||
849 | dev_kfree_skb(bch->tx_skb); | ||
850 | get_next_bframe(bch); | ||
851 | } | ||
852 | |||
853 | |||
854 | |||
855 | /* | ||
856 | * handle L1 state changes TE | ||
857 | */ | ||
858 | |||
859 | static void | ||
860 | ph_state_te(struct dchannel *dch) | ||
861 | { | ||
862 | if (dch->debug) | ||
863 | printk(KERN_DEBUG "%s: TE newstate %x\n", | ||
864 | __func__, dch->state); | ||
865 | switch (dch->state) { | ||
866 | case 0: | ||
867 | l1_event(dch->l1, HW_RESET_IND); | ||
868 | break; | ||
869 | case 3: | ||
870 | l1_event(dch->l1, HW_DEACT_IND); | ||
871 | break; | ||
872 | case 5: | ||
873 | case 8: | ||
874 | l1_event(dch->l1, ANYSIGNAL); | ||
875 | break; | ||
876 | case 6: | ||
877 | l1_event(dch->l1, INFO2); | ||
878 | break; | ||
879 | case 7: | ||
880 | l1_event(dch->l1, INFO4_P8); | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | |||
885 | /* | ||
886 | * handle L1 state changes NT | ||
887 | */ | ||
888 | |||
889 | static void | ||
890 | handle_nt_timer3(struct dchannel *dch) { | ||
891 | struct hfc_pci *hc = dch->hw; | ||
892 | |||
893 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
894 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
895 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
896 | hc->hw.nt_timer = 0; | ||
897 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
898 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
899 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
900 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
901 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
902 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
903 | } | ||
904 | |||
905 | static void | ||
906 | ph_state_nt(struct dchannel *dch) | ||
907 | { | ||
908 | struct hfc_pci *hc = dch->hw; | ||
909 | |||
910 | if (dch->debug) | ||
911 | printk(KERN_DEBUG "%s: NT newstate %x\n", | ||
912 | __func__, dch->state); | ||
913 | switch (dch->state) { | ||
914 | case 2: | ||
915 | if (hc->hw.nt_timer < 0) { | ||
916 | hc->hw.nt_timer = 0; | ||
917 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
918 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
919 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
920 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
921 | /* Clear already pending ints */ | ||
922 | if (Read_hfc(hc, HFCPCI_INT_S1)); | ||
923 | Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); | ||
924 | udelay(10); | ||
925 | Write_hfc(hc, HFCPCI_STATES, 4); | ||
926 | dch->state = 4; | ||
927 | } else if (hc->hw.nt_timer == 0) { | ||
928 | hc->hw.int_m1 |= HFCPCI_INTS_TIMER; | ||
929 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
930 | hc->hw.nt_timer = NT_T1_COUNT; | ||
931 | hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; | ||
932 | hc->hw.ctmt |= HFCPCI_TIM3_125; | ||
933 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | | ||
934 | HFCPCI_CLTIMER); | ||
935 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
936 | test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
937 | /* allow G2 -> G3 transition */ | ||
938 | Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); | ||
939 | } else { | ||
940 | Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); | ||
941 | } | ||
942 | break; | ||
943 | case 1: | ||
944 | hc->hw.nt_timer = 0; | ||
945 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
946 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
947 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
948 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
949 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
950 | hc->hw.mst_m &= ~HFCPCI_MASTER; | ||
951 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
952 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
953 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | ||
954 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
955 | break; | ||
956 | case 4: | ||
957 | hc->hw.nt_timer = 0; | ||
958 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
959 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
960 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
961 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
962 | break; | ||
963 | case 3: | ||
964 | if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) { | ||
965 | if (!test_and_clear_bit(FLG_L2_ACTIVATED, | ||
966 | &dch->Flags)) { | ||
967 | handle_nt_timer3(dch); | ||
968 | break; | ||
969 | } | ||
970 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
971 | hc->hw.int_m1 |= HFCPCI_INTS_TIMER; | ||
972 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
973 | hc->hw.nt_timer = NT_T3_COUNT; | ||
974 | hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; | ||
975 | hc->hw.ctmt |= HFCPCI_TIM3_125; | ||
976 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | | ||
977 | HFCPCI_CLTIMER); | ||
978 | } | ||
979 | break; | ||
980 | } | ||
981 | } | ||
982 | |||
983 | static void | ||
984 | ph_state(struct dchannel *dch) | ||
985 | { | ||
986 | struct hfc_pci *hc = dch->hw; | ||
987 | |||
988 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
989 | if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) && | ||
990 | hc->hw.nt_timer < 0) | ||
991 | handle_nt_timer3(dch); | ||
992 | else | ||
993 | ph_state_nt(dch); | ||
994 | } else | ||
995 | ph_state_te(dch); | ||
996 | } | ||
997 | |||
998 | /* | ||
999 | * Layer 1 callback function | ||
1000 | */ | ||
1001 | static int | ||
1002 | hfc_l1callback(struct dchannel *dch, u_int cmd) | ||
1003 | { | ||
1004 | struct hfc_pci *hc = dch->hw; | ||
1005 | |||
1006 | switch (cmd) { | ||
1007 | case INFO3_P8: | ||
1008 | case INFO3_P10: | ||
1009 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
1010 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
1011 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
1012 | break; | ||
1013 | case HW_RESET_REQ: | ||
1014 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); | ||
1015 | /* HFC ST 3 */ | ||
1016 | udelay(6); | ||
1017 | Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ | ||
1018 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
1019 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
1020 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
1021 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | | ||
1022 | HFCPCI_DO_ACTION); | ||
1023 | l1_event(dch->l1, HW_POWERUP_IND); | ||
1024 | break; | ||
1025 | case HW_DEACT_REQ: | ||
1026 | hc->hw.mst_m &= ~HFCPCI_MASTER; | ||
1027 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
1028 | skb_queue_purge(&dch->squeue); | ||
1029 | if (dch->tx_skb) { | ||
1030 | dev_kfree_skb(dch->tx_skb); | ||
1031 | dch->tx_skb = NULL; | ||
1032 | } | ||
1033 | dch->tx_idx = 0; | ||
1034 | if (dch->rx_skb) { | ||
1035 | dev_kfree_skb(dch->rx_skb); | ||
1036 | dch->rx_skb = NULL; | ||
1037 | } | ||
1038 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
1039 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
1040 | del_timer(&dch->timer); | ||
1041 | break; | ||
1042 | case HW_POWERUP_REQ: | ||
1043 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); | ||
1044 | break; | ||
1045 | case PH_ACTIVATE_IND: | ||
1046 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
1047 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
1048 | GFP_ATOMIC); | ||
1049 | break; | ||
1050 | case PH_DEACTIVATE_IND: | ||
1051 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
1052 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
1053 | GFP_ATOMIC); | ||
1054 | break; | ||
1055 | default: | ||
1056 | if (dch->debug & DEBUG_HW) | ||
1057 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
1058 | __func__, cmd); | ||
1059 | return -1; | ||
1060 | } | ||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | /* | ||
1065 | * Interrupt handler | ||
1066 | */ | ||
1067 | static inline void | ||
1068 | tx_birq(struct bchannel *bch) | ||
1069 | { | ||
1070 | if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) | ||
1071 | hfcpci_fill_fifo(bch); | ||
1072 | else { | ||
1073 | if (bch->tx_skb) | ||
1074 | dev_kfree_skb(bch->tx_skb); | ||
1075 | if (get_next_bframe(bch)) | ||
1076 | hfcpci_fill_fifo(bch); | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | static inline void | ||
1081 | tx_dirq(struct dchannel *dch) | ||
1082 | { | ||
1083 | if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) | ||
1084 | hfcpci_fill_dfifo(dch->hw); | ||
1085 | else { | ||
1086 | if (dch->tx_skb) | ||
1087 | dev_kfree_skb(dch->tx_skb); | ||
1088 | if (get_next_dframe(dch)) | ||
1089 | hfcpci_fill_dfifo(dch->hw); | ||
1090 | } | ||
1091 | } | ||
1092 | |||
1093 | static irqreturn_t | ||
1094 | hfcpci_int(int intno, void *dev_id) | ||
1095 | { | ||
1096 | struct hfc_pci *hc = dev_id; | ||
1097 | u_char exval; | ||
1098 | struct bchannel *bch; | ||
1099 | u_char val, stat; | ||
1100 | |||
1101 | spin_lock(&hc->lock); | ||
1102 | if (!(hc->hw.int_m2 & 0x08)) { | ||
1103 | spin_unlock(&hc->lock); | ||
1104 | return IRQ_NONE; /* not initialised */ | ||
1105 | } | ||
1106 | stat = Read_hfc(hc, HFCPCI_STATUS); | ||
1107 | if (HFCPCI_ANYINT & stat) { | ||
1108 | val = Read_hfc(hc, HFCPCI_INT_S1); | ||
1109 | if (hc->dch.debug & DEBUG_HW_DCHANNEL) | ||
1110 | printk(KERN_DEBUG | ||
1111 | "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val); | ||
1112 | } else { | ||
1113 | /* shared */ | ||
1114 | spin_unlock(&hc->lock); | ||
1115 | return IRQ_NONE; | ||
1116 | } | ||
1117 | hc->irqcnt++; | ||
1118 | |||
1119 | if (hc->dch.debug & DEBUG_HW_DCHANNEL) | ||
1120 | printk(KERN_DEBUG "HFC-PCI irq %x\n", val); | ||
1121 | val &= hc->hw.int_m1; | ||
1122 | if (val & 0x40) { /* state machine irq */ | ||
1123 | exval = Read_hfc(hc, HFCPCI_STATES) & 0xf; | ||
1124 | if (hc->dch.debug & DEBUG_HW_DCHANNEL) | ||
1125 | printk(KERN_DEBUG "ph_state chg %d->%d\n", | ||
1126 | hc->dch.state, exval); | ||
1127 | hc->dch.state = exval; | ||
1128 | schedule_event(&hc->dch, FLG_PHCHANGE); | ||
1129 | val &= ~0x40; | ||
1130 | } | ||
1131 | if (val & 0x80) { /* timer irq */ | ||
1132 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
1133 | if ((--hc->hw.nt_timer) < 0) | ||
1134 | schedule_event(&hc->dch, FLG_PHCHANGE); | ||
1135 | } | ||
1136 | val &= ~0x80; | ||
1137 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); | ||
1138 | } | ||
1139 | if (val & 0x08) { | ||
1140 | bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); | ||
1141 | if (bch) | ||
1142 | main_rec_hfcpci(bch); | ||
1143 | else if (hc->dch.debug) | ||
1144 | printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); | ||
1145 | } | ||
1146 | if (val & 0x10) { | ||
1147 | bch = Sel_BCS(hc, 2); | ||
1148 | if (bch) | ||
1149 | main_rec_hfcpci(bch); | ||
1150 | else if (hc->dch.debug) | ||
1151 | printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); | ||
1152 | } | ||
1153 | if (val & 0x01) { | ||
1154 | bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); | ||
1155 | if (bch) | ||
1156 | tx_birq(bch); | ||
1157 | else if (hc->dch.debug) | ||
1158 | printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); | ||
1159 | } | ||
1160 | if (val & 0x02) { | ||
1161 | bch = Sel_BCS(hc, 2); | ||
1162 | if (bch) | ||
1163 | tx_birq(bch); | ||
1164 | else if (hc->dch.debug) | ||
1165 | printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); | ||
1166 | } | ||
1167 | if (val & 0x20) | ||
1168 | receive_dmsg(hc); | ||
1169 | if (val & 0x04) { /* dframe transmitted */ | ||
1170 | if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) | ||
1171 | del_timer(&hc->dch.timer); | ||
1172 | tx_dirq(&hc->dch); | ||
1173 | } | ||
1174 | spin_unlock(&hc->lock); | ||
1175 | return IRQ_HANDLED; | ||
1176 | } | ||
1177 | |||
1178 | /* | ||
1179 | * timer callback for D-chan busy resolution. Currently no function | ||
1180 | */ | ||
1181 | static void | ||
1182 | hfcpci_dbusy_timer(struct hfc_pci *hc) | ||
1183 | { | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * activate/deactivate hardware for selected channels and mode | ||
1188 | */ | ||
1189 | static int | ||
1190 | mode_hfcpci(struct bchannel *bch, int bc, int protocol) | ||
1191 | { | ||
1192 | struct hfc_pci *hc = bch->hw; | ||
1193 | int fifo2; | ||
1194 | u_char rx_slot = 0, tx_slot = 0, pcm_mode; | ||
1195 | |||
1196 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
1197 | printk(KERN_DEBUG | ||
1198 | "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n", | ||
1199 | bch->state, protocol, bch->nr, bc); | ||
1200 | |||
1201 | fifo2 = bc; | ||
1202 | pcm_mode = (bc>>24) & 0xff; | ||
1203 | if (pcm_mode) { /* PCM SLOT USE */ | ||
1204 | if (!test_bit(HFC_CFG_PCM, &hc->cfg)) | ||
1205 | printk(KERN_WARNING | ||
1206 | "%s: pcm channel id without HFC_CFG_PCM\n", | ||
1207 | __func__); | ||
1208 | rx_slot = (bc>>8) & 0xff; | ||
1209 | tx_slot = (bc>>16) & 0xff; | ||
1210 | bc = bc & 0xff; | ||
1211 | } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && | ||
1212 | (protocol > ISDN_P_NONE)) | ||
1213 | printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", | ||
1214 | __func__); | ||
1215 | if (hc->chanlimit > 1) { | ||
1216 | hc->hw.bswapped = 0; /* B1 and B2 normal mode */ | ||
1217 | hc->hw.sctrl_e &= ~0x80; | ||
1218 | } else { | ||
1219 | if (bc & 2) { | ||
1220 | if (protocol != ISDN_P_NONE) { | ||
1221 | hc->hw.bswapped = 1; /* B1 and B2 exchanged */ | ||
1222 | hc->hw.sctrl_e |= 0x80; | ||
1223 | } else { | ||
1224 | hc->hw.bswapped = 0; /* B1 and B2 normal mode */ | ||
1225 | hc->hw.sctrl_e &= ~0x80; | ||
1226 | } | ||
1227 | fifo2 = 1; | ||
1228 | } else { | ||
1229 | hc->hw.bswapped = 0; /* B1 and B2 normal mode */ | ||
1230 | hc->hw.sctrl_e &= ~0x80; | ||
1231 | } | ||
1232 | } | ||
1233 | switch (protocol) { | ||
1234 | case (-1): /* used for init */ | ||
1235 | bch->state = -1; | ||
1236 | bch->nr = bc; | ||
1237 | case (ISDN_P_NONE): | ||
1238 | if (bch->state == ISDN_P_NONE) | ||
1239 | return 0; | ||
1240 | if (bc & 2) { | ||
1241 | hc->hw.sctrl &= ~SCTRL_B2_ENA; | ||
1242 | hc->hw.sctrl_r &= ~SCTRL_B2_ENA; | ||
1243 | } else { | ||
1244 | hc->hw.sctrl &= ~SCTRL_B1_ENA; | ||
1245 | hc->hw.sctrl_r &= ~SCTRL_B1_ENA; | ||
1246 | } | ||
1247 | if (fifo2 & 2) { | ||
1248 | hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; | ||
1249 | hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + | ||
1250 | HFCPCI_INTS_B2REC); | ||
1251 | } else { | ||
1252 | hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; | ||
1253 | hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + | ||
1254 | HFCPCI_INTS_B1REC); | ||
1255 | } | ||
1256 | #ifdef REVERSE_BITORDER | ||
1257 | if (bch->nr & 2) | ||
1258 | hc->hw.cirm &= 0x7f; | ||
1259 | else | ||
1260 | hc->hw.cirm &= 0xbf; | ||
1261 | #endif | ||
1262 | bch->state = ISDN_P_NONE; | ||
1263 | bch->nr = bc; | ||
1264 | test_and_clear_bit(FLG_HDLC, &bch->Flags); | ||
1265 | test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); | ||
1266 | break; | ||
1267 | case (ISDN_P_B_RAW): | ||
1268 | bch->state = protocol; | ||
1269 | bch->nr = bc; | ||
1270 | hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); | ||
1271 | hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); | ||
1272 | if (bc & 2) { | ||
1273 | hc->hw.sctrl |= SCTRL_B2_ENA; | ||
1274 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
1275 | #ifdef REVERSE_BITORDER | ||
1276 | hc->hw.cirm |= 0x80; | ||
1277 | #endif | ||
1278 | } else { | ||
1279 | hc->hw.sctrl |= SCTRL_B1_ENA; | ||
1280 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
1281 | #ifdef REVERSE_BITORDER | ||
1282 | hc->hw.cirm |= 0x40; | ||
1283 | #endif | ||
1284 | } | ||
1285 | if (fifo2 & 2) { | ||
1286 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; | ||
1287 | hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + | ||
1288 | HFCPCI_INTS_B2REC); | ||
1289 | hc->hw.ctmt |= 2; | ||
1290 | hc->hw.conn &= ~0x18; | ||
1291 | } else { | ||
1292 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; | ||
1293 | hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + | ||
1294 | HFCPCI_INTS_B1REC); | ||
1295 | hc->hw.ctmt |= 1; | ||
1296 | hc->hw.conn &= ~0x03; | ||
1297 | } | ||
1298 | test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); | ||
1299 | break; | ||
1300 | case (ISDN_P_B_HDLC): | ||
1301 | bch->state = protocol; | ||
1302 | bch->nr = bc; | ||
1303 | hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); | ||
1304 | hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); | ||
1305 | if (bc & 2) { | ||
1306 | hc->hw.sctrl |= SCTRL_B2_ENA; | ||
1307 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
1308 | } else { | ||
1309 | hc->hw.sctrl |= SCTRL_B1_ENA; | ||
1310 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
1311 | } | ||
1312 | if (fifo2 & 2) { | ||
1313 | hc->hw.last_bfifo_cnt[1] = 0; | ||
1314 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; | ||
1315 | hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + | ||
1316 | HFCPCI_INTS_B2REC); | ||
1317 | hc->hw.ctmt &= ~2; | ||
1318 | hc->hw.conn &= ~0x18; | ||
1319 | } else { | ||
1320 | hc->hw.last_bfifo_cnt[0] = 0; | ||
1321 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; | ||
1322 | hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + | ||
1323 | HFCPCI_INTS_B1REC); | ||
1324 | hc->hw.ctmt &= ~1; | ||
1325 | hc->hw.conn &= ~0x03; | ||
1326 | } | ||
1327 | test_and_set_bit(FLG_HDLC, &bch->Flags); | ||
1328 | break; | ||
1329 | default: | ||
1330 | printk(KERN_DEBUG "prot not known %x\n", protocol); | ||
1331 | return -ENOPROTOOPT; | ||
1332 | } | ||
1333 | if (test_bit(HFC_CFG_PCM, &hc->cfg)) { | ||
1334 | if ((protocol == ISDN_P_NONE) || | ||
1335 | (protocol == -1)) { /* init case */ | ||
1336 | rx_slot = 0; | ||
1337 | tx_slot = 0; | ||
1338 | } else { | ||
1339 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { | ||
1340 | rx_slot |= 0xC0; | ||
1341 | tx_slot |= 0xC0; | ||
1342 | } else { | ||
1343 | rx_slot |= 0x80; | ||
1344 | tx_slot |= 0x80; | ||
1345 | } | ||
1346 | } | ||
1347 | if (bc & 2) { | ||
1348 | hc->hw.conn &= 0xc7; | ||
1349 | hc->hw.conn |= 0x08; | ||
1350 | printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n", | ||
1351 | __func__, tx_slot); | ||
1352 | printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n", | ||
1353 | __func__, rx_slot); | ||
1354 | Write_hfc(hc, HFCPCI_B2_SSL, tx_slot); | ||
1355 | Write_hfc(hc, HFCPCI_B2_RSL, rx_slot); | ||
1356 | } else { | ||
1357 | hc->hw.conn &= 0xf8; | ||
1358 | hc->hw.conn |= 0x01; | ||
1359 | printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n", | ||
1360 | __func__, tx_slot); | ||
1361 | printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n", | ||
1362 | __func__, rx_slot); | ||
1363 | Write_hfc(hc, HFCPCI_B1_SSL, tx_slot); | ||
1364 | Write_hfc(hc, HFCPCI_B1_RSL, rx_slot); | ||
1365 | } | ||
1366 | } | ||
1367 | Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); | ||
1368 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
1369 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
1370 | Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); | ||
1371 | Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); | ||
1372 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); | ||
1373 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1374 | #ifdef REVERSE_BITORDER | ||
1375 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
1376 | #endif | ||
1377 | return 0; | ||
1378 | } | ||
1379 | |||
1380 | static int | ||
1381 | set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) | ||
1382 | { | ||
1383 | struct hfc_pci *hc = bch->hw; | ||
1384 | |||
1385 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
1386 | printk(KERN_DEBUG | ||
1387 | "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n", | ||
1388 | bch->state, protocol, bch->nr, chan); | ||
1389 | if (bch->nr != chan) { | ||
1390 | printk(KERN_DEBUG | ||
1391 | "HFCPCI rxtest wrong channel parameter %x/%x\n", | ||
1392 | bch->nr, chan); | ||
1393 | return -EINVAL; | ||
1394 | } | ||
1395 | switch (protocol) { | ||
1396 | case (ISDN_P_B_RAW): | ||
1397 | bch->state = protocol; | ||
1398 | hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); | ||
1399 | if (chan & 2) { | ||
1400 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
1401 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; | ||
1402 | hc->hw.int_m1 |= HFCPCI_INTS_B2REC; | ||
1403 | hc->hw.ctmt |= 2; | ||
1404 | hc->hw.conn &= ~0x18; | ||
1405 | #ifdef REVERSE_BITORDER | ||
1406 | hc->hw.cirm |= 0x80; | ||
1407 | #endif | ||
1408 | } else { | ||
1409 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
1410 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; | ||
1411 | hc->hw.int_m1 |= HFCPCI_INTS_B1REC; | ||
1412 | hc->hw.ctmt |= 1; | ||
1413 | hc->hw.conn &= ~0x03; | ||
1414 | #ifdef REVERSE_BITORDER | ||
1415 | hc->hw.cirm |= 0x40; | ||
1416 | #endif | ||
1417 | } | ||
1418 | break; | ||
1419 | case (ISDN_P_B_HDLC): | ||
1420 | bch->state = protocol; | ||
1421 | hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); | ||
1422 | if (chan & 2) { | ||
1423 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
1424 | hc->hw.last_bfifo_cnt[1] = 0; | ||
1425 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; | ||
1426 | hc->hw.int_m1 |= HFCPCI_INTS_B2REC; | ||
1427 | hc->hw.ctmt &= ~2; | ||
1428 | hc->hw.conn &= ~0x18; | ||
1429 | } else { | ||
1430 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
1431 | hc->hw.last_bfifo_cnt[0] = 0; | ||
1432 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; | ||
1433 | hc->hw.int_m1 |= HFCPCI_INTS_B1REC; | ||
1434 | hc->hw.ctmt &= ~1; | ||
1435 | hc->hw.conn &= ~0x03; | ||
1436 | } | ||
1437 | break; | ||
1438 | default: | ||
1439 | printk(KERN_DEBUG "prot not known %x\n", protocol); | ||
1440 | return -ENOPROTOOPT; | ||
1441 | } | ||
1442 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
1443 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
1444 | Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); | ||
1445 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); | ||
1446 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1447 | #ifdef REVERSE_BITORDER | ||
1448 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
1449 | #endif | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | static void | ||
1454 | deactivate_bchannel(struct bchannel *bch) | ||
1455 | { | ||
1456 | struct hfc_pci *hc = bch->hw; | ||
1457 | u_long flags; | ||
1458 | |||
1459 | spin_lock_irqsave(&hc->lock, flags); | ||
1460 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
1461 | dev_kfree_skb(bch->next_skb); | ||
1462 | bch->next_skb = NULL; | ||
1463 | } | ||
1464 | if (bch->tx_skb) { | ||
1465 | dev_kfree_skb(bch->tx_skb); | ||
1466 | bch->tx_skb = NULL; | ||
1467 | } | ||
1468 | bch->tx_idx = 0; | ||
1469 | if (bch->rx_skb) { | ||
1470 | dev_kfree_skb(bch->rx_skb); | ||
1471 | bch->rx_skb = NULL; | ||
1472 | } | ||
1473 | mode_hfcpci(bch, bch->nr, ISDN_P_NONE); | ||
1474 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1475 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
1476 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1477 | } | ||
1478 | |||
1479 | /* | ||
1480 | * Layer 1 B-channel hardware access | ||
1481 | */ | ||
1482 | static int | ||
1483 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
1484 | { | ||
1485 | int ret = 0; | ||
1486 | |||
1487 | switch (cq->op) { | ||
1488 | case MISDN_CTRL_GETOP: | ||
1489 | cq->op = 0; | ||
1490 | break; | ||
1491 | default: | ||
1492 | printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); | ||
1493 | ret = -EINVAL; | ||
1494 | break; | ||
1495 | } | ||
1496 | return ret; | ||
1497 | } | ||
1498 | static int | ||
1499 | hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1500 | { | ||
1501 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1502 | struct hfc_pci *hc = bch->hw; | ||
1503 | int ret = -EINVAL; | ||
1504 | u_long flags; | ||
1505 | |||
1506 | if (bch->debug & DEBUG_HW) | ||
1507 | printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); | ||
1508 | switch (cmd) { | ||
1509 | case HW_TESTRX_RAW: | ||
1510 | spin_lock_irqsave(&hc->lock, flags); | ||
1511 | ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg); | ||
1512 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1513 | break; | ||
1514 | case HW_TESTRX_HDLC: | ||
1515 | spin_lock_irqsave(&hc->lock, flags); | ||
1516 | ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg); | ||
1517 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1518 | break; | ||
1519 | case HW_TESTRX_OFF: | ||
1520 | spin_lock_irqsave(&hc->lock, flags); | ||
1521 | mode_hfcpci(bch, bch->nr, ISDN_P_NONE); | ||
1522 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1523 | ret = 0; | ||
1524 | break; | ||
1525 | case CLOSE_CHANNEL: | ||
1526 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
1527 | if (test_bit(FLG_ACTIVE, &bch->Flags)) | ||
1528 | deactivate_bchannel(bch); | ||
1529 | ch->protocol = ISDN_P_NONE; | ||
1530 | ch->peer = NULL; | ||
1531 | module_put(THIS_MODULE); | ||
1532 | ret = 0; | ||
1533 | break; | ||
1534 | case CONTROL_CHANNEL: | ||
1535 | ret = channel_bctrl(bch, arg); | ||
1536 | break; | ||
1537 | default: | ||
1538 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
1539 | __func__, cmd); | ||
1540 | } | ||
1541 | return ret; | ||
1542 | } | ||
1543 | |||
1544 | /* | ||
1545 | * Layer2 -> Layer 1 Dchannel data | ||
1546 | */ | ||
1547 | static int | ||
1548 | hfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1549 | { | ||
1550 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1551 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1552 | struct hfc_pci *hc = dch->hw; | ||
1553 | int ret = -EINVAL; | ||
1554 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1555 | unsigned int id; | ||
1556 | u_long flags; | ||
1557 | |||
1558 | switch (hh->prim) { | ||
1559 | case PH_DATA_REQ: | ||
1560 | spin_lock_irqsave(&hc->lock, flags); | ||
1561 | ret = dchannel_senddata(dch, skb); | ||
1562 | if (ret > 0) { /* direct TX */ | ||
1563 | id = hh->id; /* skb can be freed */ | ||
1564 | hfcpci_fill_dfifo(dch->hw); | ||
1565 | ret = 0; | ||
1566 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1567 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
1568 | } else | ||
1569 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1570 | return ret; | ||
1571 | case PH_ACTIVATE_REQ: | ||
1572 | spin_lock_irqsave(&hc->lock, flags); | ||
1573 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
1574 | ret = 0; | ||
1575 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
1576 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
1577 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
1578 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
1579 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1580 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
1581 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
1582 | break; | ||
1583 | } | ||
1584 | test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
1585 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | | ||
1586 | HFCPCI_DO_ACTION | 1); | ||
1587 | } else | ||
1588 | ret = l1_event(dch->l1, hh->prim); | ||
1589 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1590 | break; | ||
1591 | case PH_DEACTIVATE_REQ: | ||
1592 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
1593 | spin_lock_irqsave(&hc->lock, flags); | ||
1594 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
1595 | /* prepare deactivation */ | ||
1596 | Write_hfc(hc, HFCPCI_STATES, 0x40); | ||
1597 | skb_queue_purge(&dch->squeue); | ||
1598 | if (dch->tx_skb) { | ||
1599 | dev_kfree_skb(dch->tx_skb); | ||
1600 | dch->tx_skb = NULL; | ||
1601 | } | ||
1602 | dch->tx_idx = 0; | ||
1603 | if (dch->rx_skb) { | ||
1604 | dev_kfree_skb(dch->rx_skb); | ||
1605 | dch->rx_skb = NULL; | ||
1606 | } | ||
1607 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
1608 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
1609 | del_timer(&dch->timer); | ||
1610 | #ifdef FIXME | ||
1611 | if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) | ||
1612 | dchannel_sched_event(&hc->dch, D_CLEARBUSY); | ||
1613 | #endif | ||
1614 | hc->hw.mst_m &= ~HFCPCI_MASTER; | ||
1615 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
1616 | ret = 0; | ||
1617 | } else { | ||
1618 | ret = l1_event(dch->l1, hh->prim); | ||
1619 | } | ||
1620 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1621 | break; | ||
1622 | } | ||
1623 | if (!ret) | ||
1624 | dev_kfree_skb(skb); | ||
1625 | return ret; | ||
1626 | } | ||
1627 | |||
1628 | /* | ||
1629 | * Layer2 -> Layer 1 Bchannel data | ||
1630 | */ | ||
1631 | static int | ||
1632 | hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1633 | { | ||
1634 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1635 | struct hfc_pci *hc = bch->hw; | ||
1636 | int ret = -EINVAL; | ||
1637 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1638 | unsigned int id; | ||
1639 | u_long flags; | ||
1640 | |||
1641 | switch (hh->prim) { | ||
1642 | case PH_DATA_REQ: | ||
1643 | spin_lock_irqsave(&hc->lock, flags); | ||
1644 | ret = bchannel_senddata(bch, skb); | ||
1645 | if (ret > 0) { /* direct TX */ | ||
1646 | id = hh->id; /* skb can be freed */ | ||
1647 | hfcpci_fill_fifo(bch); | ||
1648 | ret = 0; | ||
1649 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1650 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
1651 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
1652 | } else | ||
1653 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1654 | return ret; | ||
1655 | case PH_ACTIVATE_REQ: | ||
1656 | spin_lock_irqsave(&hc->lock, flags); | ||
1657 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
1658 | ret = mode_hfcpci(bch, bch->nr, ch->protocol); | ||
1659 | else | ||
1660 | ret = 0; | ||
1661 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1662 | if (!ret) | ||
1663 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
1664 | NULL, GFP_KERNEL); | ||
1665 | break; | ||
1666 | case PH_DEACTIVATE_REQ: | ||
1667 | deactivate_bchannel(bch); | ||
1668 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
1669 | NULL, GFP_KERNEL); | ||
1670 | ret = 0; | ||
1671 | break; | ||
1672 | } | ||
1673 | if (!ret) | ||
1674 | dev_kfree_skb(skb); | ||
1675 | return ret; | ||
1676 | } | ||
1677 | |||
1678 | /* | ||
1679 | * called for card init message | ||
1680 | */ | ||
1681 | |||
1682 | void | ||
1683 | inithfcpci(struct hfc_pci *hc) | ||
1684 | { | ||
1685 | printk(KERN_DEBUG "inithfcpci: entered\n"); | ||
1686 | hc->dch.timer.function = (void *) hfcpci_dbusy_timer; | ||
1687 | hc->dch.timer.data = (long) &hc->dch; | ||
1688 | init_timer(&hc->dch.timer); | ||
1689 | hc->chanlimit = 2; | ||
1690 | mode_hfcpci(&hc->bch[0], 1, -1); | ||
1691 | mode_hfcpci(&hc->bch[1], 2, -1); | ||
1692 | } | ||
1693 | |||
1694 | |||
1695 | static int | ||
1696 | init_card(struct hfc_pci *hc) | ||
1697 | { | ||
1698 | int cnt = 3; | ||
1699 | u_long flags; | ||
1700 | |||
1701 | printk(KERN_DEBUG "init_card: entered\n"); | ||
1702 | |||
1703 | |||
1704 | spin_lock_irqsave(&hc->lock, flags); | ||
1705 | disable_hwirq(hc); | ||
1706 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1707 | if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) { | ||
1708 | printk(KERN_WARNING | ||
1709 | "mISDN: couldn't get interrupt %d\n", hc->irq); | ||
1710 | return -EIO; | ||
1711 | } | ||
1712 | spin_lock_irqsave(&hc->lock, flags); | ||
1713 | reset_hfcpci(hc); | ||
1714 | while (cnt) { | ||
1715 | inithfcpci(hc); | ||
1716 | /* | ||
1717 | * Finally enable IRQ output | ||
1718 | * this is only allowed, if an IRQ routine is allready | ||
1719 | * established for this HFC, so don't do that earlier | ||
1720 | */ | ||
1721 | enable_hwirq(hc); | ||
1722 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1723 | /* Timeout 80ms */ | ||
1724 | current->state = TASK_UNINTERRUPTIBLE; | ||
1725 | schedule_timeout((80*HZ)/1000); | ||
1726 | printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", | ||
1727 | hc->irq, hc->irqcnt); | ||
1728 | /* now switch timer interrupt off */ | ||
1729 | spin_lock_irqsave(&hc->lock, flags); | ||
1730 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
1731 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
1732 | /* reinit mode reg */ | ||
1733 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
1734 | if (!hc->irqcnt) { | ||
1735 | printk(KERN_WARNING | ||
1736 | "HFC PCI: IRQ(%d) getting no interrupts " | ||
1737 | "during init %d\n", hc->irq, 4 - cnt); | ||
1738 | if (cnt == 1) { | ||
1739 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1740 | return -EIO; | ||
1741 | } else { | ||
1742 | reset_hfcpci(hc); | ||
1743 | cnt--; | ||
1744 | } | ||
1745 | } else { | ||
1746 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1747 | hc->initdone = 1; | ||
1748 | return 0; | ||
1749 | } | ||
1750 | } | ||
1751 | disable_hwirq(hc); | ||
1752 | spin_unlock_irqrestore(&hc->lock, flags); | ||
1753 | free_irq(hc->irq, hc); | ||
1754 | return -EIO; | ||
1755 | } | ||
1756 | |||
1757 | static int | ||
1758 | channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) | ||
1759 | { | ||
1760 | int ret = 0; | ||
1761 | u_char slot; | ||
1762 | |||
1763 | switch (cq->op) { | ||
1764 | case MISDN_CTRL_GETOP: | ||
1765 | cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | | ||
1766 | MISDN_CTRL_DISCONNECT; | ||
1767 | break; | ||
1768 | case MISDN_CTRL_LOOP: | ||
1769 | /* channel 0 disabled loop */ | ||
1770 | if (cq->channel < 0 || cq->channel > 2) { | ||
1771 | ret = -EINVAL; | ||
1772 | break; | ||
1773 | } | ||
1774 | if (cq->channel & 1) { | ||
1775 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
1776 | slot = 0xC0; | ||
1777 | else | ||
1778 | slot = 0x80; | ||
1779 | printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", | ||
1780 | __func__, slot); | ||
1781 | Write_hfc(hc, HFCPCI_B1_SSL, slot); | ||
1782 | Write_hfc(hc, HFCPCI_B1_RSL, slot); | ||
1783 | hc->hw.conn = (hc->hw.conn & ~7) | 6; | ||
1784 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1785 | } | ||
1786 | if (cq->channel & 2) { | ||
1787 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
1788 | slot = 0xC1; | ||
1789 | else | ||
1790 | slot = 0x81; | ||
1791 | printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", | ||
1792 | __func__, slot); | ||
1793 | Write_hfc(hc, HFCPCI_B2_SSL, slot); | ||
1794 | Write_hfc(hc, HFCPCI_B2_RSL, slot); | ||
1795 | hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30; | ||
1796 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1797 | } | ||
1798 | if (cq->channel & 3) | ||
1799 | hc->hw.trm |= 0x80; /* enable IOM-loop */ | ||
1800 | else { | ||
1801 | hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; | ||
1802 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1803 | hc->hw.trm &= 0x7f; /* disable IOM-loop */ | ||
1804 | } | ||
1805 | Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); | ||
1806 | break; | ||
1807 | case MISDN_CTRL_CONNECT: | ||
1808 | if (cq->channel == cq->p1) { | ||
1809 | ret = -EINVAL; | ||
1810 | break; | ||
1811 | } | ||
1812 | if (cq->channel < 1 || cq->channel > 2 || | ||
1813 | cq->p1 < 1 || cq->p1 > 2) { | ||
1814 | ret = -EINVAL; | ||
1815 | break; | ||
1816 | } | ||
1817 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
1818 | slot = 0xC0; | ||
1819 | else | ||
1820 | slot = 0x80; | ||
1821 | printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", | ||
1822 | __func__, slot); | ||
1823 | Write_hfc(hc, HFCPCI_B1_SSL, slot); | ||
1824 | Write_hfc(hc, HFCPCI_B2_RSL, slot); | ||
1825 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
1826 | slot = 0xC1; | ||
1827 | else | ||
1828 | slot = 0x81; | ||
1829 | printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", | ||
1830 | __func__, slot); | ||
1831 | Write_hfc(hc, HFCPCI_B2_SSL, slot); | ||
1832 | Write_hfc(hc, HFCPCI_B1_RSL, slot); | ||
1833 | hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36; | ||
1834 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1835 | hc->hw.trm |= 0x80; | ||
1836 | Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); | ||
1837 | break; | ||
1838 | case MISDN_CTRL_DISCONNECT: | ||
1839 | hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; | ||
1840 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
1841 | hc->hw.trm &= 0x7f; /* disable IOM-loop */ | ||
1842 | break; | ||
1843 | default: | ||
1844 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
1845 | __func__, cq->op); | ||
1846 | ret = -EINVAL; | ||
1847 | break; | ||
1848 | } | ||
1849 | return ret; | ||
1850 | } | ||
1851 | |||
1852 | static int | ||
1853 | open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, | ||
1854 | struct channel_req *rq) | ||
1855 | { | ||
1856 | int err = 0; | ||
1857 | |||
1858 | if (debug & DEBUG_HW_OPEN) | ||
1859 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
1860 | hc->dch.dev.id, __builtin_return_address(0)); | ||
1861 | if (rq->protocol == ISDN_P_NONE) | ||
1862 | return -EINVAL; | ||
1863 | if (!hc->initdone) { | ||
1864 | if (rq->protocol == ISDN_P_TE_S0) { | ||
1865 | err = create_l1(&hc->dch, hfc_l1callback); | ||
1866 | if (err) | ||
1867 | return err; | ||
1868 | } | ||
1869 | hc->hw.protocol = rq->protocol; | ||
1870 | ch->protocol = rq->protocol; | ||
1871 | err = init_card(hc); | ||
1872 | if (err) | ||
1873 | return err; | ||
1874 | } else { | ||
1875 | if (rq->protocol != ch->protocol) { | ||
1876 | if (hc->hw.protocol == ISDN_P_TE_S0) | ||
1877 | l1_event(hc->dch.l1, CLOSE_CHANNEL); | ||
1878 | hc->hw.protocol = rq->protocol; | ||
1879 | ch->protocol = rq->protocol; | ||
1880 | hfcpci_setmode(hc); | ||
1881 | } | ||
1882 | } | ||
1883 | |||
1884 | if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) || | ||
1885 | ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) { | ||
1886 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
1887 | 0, NULL, GFP_KERNEL); | ||
1888 | } | ||
1889 | rq->ch = ch; | ||
1890 | if (!try_module_get(THIS_MODULE)) | ||
1891 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
1892 | return 0; | ||
1893 | } | ||
1894 | |||
1895 | static int | ||
1896 | open_bchannel(struct hfc_pci *hc, struct channel_req *rq) | ||
1897 | { | ||
1898 | struct bchannel *bch; | ||
1899 | |||
1900 | if (rq->adr.channel > 2) | ||
1901 | return -EINVAL; | ||
1902 | if (rq->protocol == ISDN_P_NONE) | ||
1903 | return -EINVAL; | ||
1904 | bch = &hc->bch[rq->adr.channel - 1]; | ||
1905 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
1906 | return -EBUSY; /* b-channel can be only open once */ | ||
1907 | bch->ch.protocol = rq->protocol; | ||
1908 | rq->ch = &bch->ch; /* TODO: E-channel */ | ||
1909 | if (!try_module_get(THIS_MODULE)) | ||
1910 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
1911 | return 0; | ||
1912 | } | ||
1913 | |||
1914 | /* | ||
1915 | * device control function | ||
1916 | */ | ||
1917 | static int | ||
1918 | hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1919 | { | ||
1920 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1921 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1922 | struct hfc_pci *hc = dch->hw; | ||
1923 | struct channel_req *rq; | ||
1924 | int err = 0; | ||
1925 | |||
1926 | if (dch->debug & DEBUG_HW) | ||
1927 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
1928 | __func__, cmd, arg); | ||
1929 | switch (cmd) { | ||
1930 | case OPEN_CHANNEL: | ||
1931 | rq = arg; | ||
1932 | if (rq->adr.channel == 0) | ||
1933 | err = open_dchannel(hc, ch, rq); | ||
1934 | else | ||
1935 | err = open_bchannel(hc, rq); | ||
1936 | break; | ||
1937 | case CLOSE_CHANNEL: | ||
1938 | if (debug & DEBUG_HW_OPEN) | ||
1939 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
1940 | __func__, hc->dch.dev.id, | ||
1941 | __builtin_return_address(0)); | ||
1942 | module_put(THIS_MODULE); | ||
1943 | break; | ||
1944 | case CONTROL_CHANNEL: | ||
1945 | err = channel_ctrl(hc, arg); | ||
1946 | break; | ||
1947 | default: | ||
1948 | if (dch->debug & DEBUG_HW) | ||
1949 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
1950 | __func__, cmd); | ||
1951 | return -EINVAL; | ||
1952 | } | ||
1953 | return err; | ||
1954 | } | ||
1955 | |||
1956 | static int | ||
1957 | setup_hw(struct hfc_pci *hc) | ||
1958 | { | ||
1959 | void *buffer; | ||
1960 | |||
1961 | printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision); | ||
1962 | hc->hw.cirm = 0; | ||
1963 | hc->dch.state = 0; | ||
1964 | pci_set_master(hc->pdev); | ||
1965 | if (!hc->irq) { | ||
1966 | printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); | ||
1967 | return 1; | ||
1968 | } | ||
1969 | hc->hw.pci_io = (char *)(ulong)hc->pdev->resource[1].start; | ||
1970 | |||
1971 | if (!hc->hw.pci_io) { | ||
1972 | printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); | ||
1973 | return 1; | ||
1974 | } | ||
1975 | /* Allocate memory for FIFOS */ | ||
1976 | /* the memory needs to be on a 32k boundary within the first 4G */ | ||
1977 | pci_set_dma_mask(hc->pdev, 0xFFFF8000); | ||
1978 | buffer = pci_alloc_consistent(hc->pdev, 0x8000, &hc->hw.dmahandle); | ||
1979 | /* We silently assume the address is okay if nonzero */ | ||
1980 | if (!buffer) { | ||
1981 | printk(KERN_WARNING | ||
1982 | "HFC-PCI: Error allocating memory for FIFO!\n"); | ||
1983 | return 1; | ||
1984 | } | ||
1985 | hc->hw.fifos = buffer; | ||
1986 | pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle); | ||
1987 | hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); | ||
1988 | printk(KERN_INFO | ||
1989 | "HFC-PCI: defined at mem %#lx fifo %#lx(%#lx) IRQ %d HZ %d\n", | ||
1990 | (u_long) hc->hw.pci_io, (u_long) hc->hw.fifos, | ||
1991 | (u_long) virt_to_bus(hc->hw.fifos), | ||
1992 | hc->irq, HZ); | ||
1993 | /* enable memory mapped ports, disable busmaster */ | ||
1994 | pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
1995 | hc->hw.int_m2 = 0; | ||
1996 | disable_hwirq(hc); | ||
1997 | hc->hw.int_m1 = 0; | ||
1998 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
1999 | /* At this point the needed PCI config is done */ | ||
2000 | /* fifos are still not enabled */ | ||
2001 | hc->hw.timer.function = (void *) hfcpci_Timer; | ||
2002 | hc->hw.timer.data = (long) hc; | ||
2003 | init_timer(&hc->hw.timer); | ||
2004 | /* default PCM master */ | ||
2005 | test_and_set_bit(HFC_CFG_MASTER, &hc->cfg); | ||
2006 | return 0; | ||
2007 | } | ||
2008 | |||
2009 | static void | ||
2010 | release_card(struct hfc_pci *hc) { | ||
2011 | u_long flags; | ||
2012 | |||
2013 | spin_lock_irqsave(&hc->lock, flags); | ||
2014 | hc->hw.int_m2 = 0; /* interrupt output off ! */ | ||
2015 | disable_hwirq(hc); | ||
2016 | mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE); | ||
2017 | mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE); | ||
2018 | if (hc->dch.timer.function != NULL) { | ||
2019 | del_timer(&hc->dch.timer); | ||
2020 | hc->dch.timer.function = NULL; | ||
2021 | } | ||
2022 | spin_unlock_irqrestore(&hc->lock, flags); | ||
2023 | if (hc->hw.protocol == ISDN_P_TE_S0) | ||
2024 | l1_event(hc->dch.l1, CLOSE_CHANNEL); | ||
2025 | if (hc->initdone) | ||
2026 | free_irq(hc->irq, hc); | ||
2027 | release_io_hfcpci(hc); /* must release after free_irq! */ | ||
2028 | mISDN_unregister_device(&hc->dch.dev); | ||
2029 | mISDN_freebchannel(&hc->bch[1]); | ||
2030 | mISDN_freebchannel(&hc->bch[0]); | ||
2031 | mISDN_freedchannel(&hc->dch); | ||
2032 | list_del(&hc->list); | ||
2033 | pci_set_drvdata(hc->pdev, NULL); | ||
2034 | kfree(hc); | ||
2035 | } | ||
2036 | |||
2037 | static int | ||
2038 | setup_card(struct hfc_pci *card) | ||
2039 | { | ||
2040 | int err = -EINVAL; | ||
2041 | u_int i; | ||
2042 | u_long flags; | ||
2043 | char name[MISDN_MAX_IDLEN]; | ||
2044 | |||
2045 | if (HFC_cnt >= MAX_CARDS) | ||
2046 | return -EINVAL; /* maybe better value */ | ||
2047 | |||
2048 | card->dch.debug = debug; | ||
2049 | spin_lock_init(&card->lock); | ||
2050 | mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); | ||
2051 | card->dch.hw = card; | ||
2052 | card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
2053 | card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
2054 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
2055 | card->dch.dev.D.send = hfcpci_l2l1D; | ||
2056 | card->dch.dev.D.ctrl = hfc_dctrl; | ||
2057 | card->dch.dev.nrbchan = 2; | ||
2058 | for (i = 0; i < 2; i++) { | ||
2059 | card->bch[i].nr = i + 1; | ||
2060 | test_and_set_bit(i + 1, &card->dch.dev.channelmap[0]); | ||
2061 | card->bch[i].debug = debug; | ||
2062 | mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); | ||
2063 | card->bch[i].hw = card; | ||
2064 | card->bch[i].ch.send = hfcpci_l2l1B; | ||
2065 | card->bch[i].ch.ctrl = hfc_bctrl; | ||
2066 | card->bch[i].ch.nr = i + 1; | ||
2067 | list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels); | ||
2068 | } | ||
2069 | err = setup_hw(card); | ||
2070 | if (err) | ||
2071 | goto error; | ||
2072 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); | ||
2073 | err = mISDN_register_device(&card->dch.dev, name); | ||
2074 | if (err) | ||
2075 | goto error; | ||
2076 | HFC_cnt++; | ||
2077 | write_lock_irqsave(&HFClock, flags); | ||
2078 | list_add_tail(&card->list, &HFClist); | ||
2079 | write_unlock_irqrestore(&HFClock, flags); | ||
2080 | printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); | ||
2081 | return 0; | ||
2082 | error: | ||
2083 | mISDN_freebchannel(&card->bch[1]); | ||
2084 | mISDN_freebchannel(&card->bch[0]); | ||
2085 | mISDN_freedchannel(&card->dch); | ||
2086 | kfree(card); | ||
2087 | return err; | ||
2088 | } | ||
2089 | |||
2090 | /* private data in the PCI devices list */ | ||
2091 | struct _hfc_map { | ||
2092 | u_int subtype; | ||
2093 | u_int flag; | ||
2094 | char *name; | ||
2095 | }; | ||
2096 | |||
2097 | static const struct _hfc_map hfc_map[] = | ||
2098 | { | ||
2099 | {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"}, | ||
2100 | {HFC_CCD_B000, 0, "Billion B000"}, | ||
2101 | {HFC_CCD_B006, 0, "Billion B006"}, | ||
2102 | {HFC_CCD_B007, 0, "Billion B007"}, | ||
2103 | {HFC_CCD_B008, 0, "Billion B008"}, | ||
2104 | {HFC_CCD_B009, 0, "Billion B009"}, | ||
2105 | {HFC_CCD_B00A, 0, "Billion B00A"}, | ||
2106 | {HFC_CCD_B00B, 0, "Billion B00B"}, | ||
2107 | {HFC_CCD_B00C, 0, "Billion B00C"}, | ||
2108 | {HFC_CCD_B100, 0, "Seyeon B100"}, | ||
2109 | {HFC_CCD_B700, 0, "Primux II S0 B700"}, | ||
2110 | {HFC_CCD_B701, 0, "Primux II S0 NT B701"}, | ||
2111 | {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"}, | ||
2112 | {HFC_ASUS_0675, 0, "Asuscom/Askey 675"}, | ||
2113 | {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"}, | ||
2114 | {HFC_BERKOM_A1T, 0, "German telekom A1T"}, | ||
2115 | {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"}, | ||
2116 | {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"}, | ||
2117 | {HFC_DIGI_DF_M_IOM2_E, 0, | ||
2118 | "Digi International DataFire Micro V IOM2 (Europe)"}, | ||
2119 | {HFC_DIGI_DF_M_E, 0, | ||
2120 | "Digi International DataFire Micro V (Europe)"}, | ||
2121 | {HFC_DIGI_DF_M_IOM2_A, 0, | ||
2122 | "Digi International DataFire Micro V IOM2 (North America)"}, | ||
2123 | {HFC_DIGI_DF_M_A, 0, | ||
2124 | "Digi International DataFire Micro V (North America)"}, | ||
2125 | {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"}, | ||
2126 | {}, | ||
2127 | }; | ||
2128 | |||
2129 | static struct pci_device_id hfc_ids[] = | ||
2130 | { | ||
2131 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, | ||
2132 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[0]}, | ||
2133 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, | ||
2134 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[1]}, | ||
2135 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, | ||
2136 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[2]}, | ||
2137 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, | ||
2138 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[3]}, | ||
2139 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, | ||
2140 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[4]}, | ||
2141 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, | ||
2142 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[5]}, | ||
2143 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, | ||
2144 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[6]}, | ||
2145 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, | ||
2146 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[7]}, | ||
2147 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, | ||
2148 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[8]}, | ||
2149 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, | ||
2150 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[9]}, | ||
2151 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, | ||
2152 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[10]}, | ||
2153 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, | ||
2154 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[11]}, | ||
2155 | {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, | ||
2156 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[12]}, | ||
2157 | {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, | ||
2158 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[13]}, | ||
2159 | {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, | ||
2160 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[14]}, | ||
2161 | {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, | ||
2162 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[15]}, | ||
2163 | {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, | ||
2164 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[16]}, | ||
2165 | {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, | ||
2166 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[17]}, | ||
2167 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, | ||
2168 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[18]}, | ||
2169 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, | ||
2170 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[19]}, | ||
2171 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, | ||
2172 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[20]}, | ||
2173 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, | ||
2174 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[21]}, | ||
2175 | {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, | ||
2176 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[22]}, | ||
2177 | {}, | ||
2178 | }; | ||
2179 | |||
2180 | static int __devinit | ||
2181 | hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
2182 | { | ||
2183 | int err = -ENOMEM; | ||
2184 | struct hfc_pci *card; | ||
2185 | struct _hfc_map *m = (struct _hfc_map *)ent->driver_data; | ||
2186 | |||
2187 | card = kzalloc(sizeof(struct hfc_pci), GFP_ATOMIC); | ||
2188 | if (!card) { | ||
2189 | printk(KERN_ERR "No kmem for HFC card\n"); | ||
2190 | return err; | ||
2191 | } | ||
2192 | card->pdev = pdev; | ||
2193 | card->subtype = m->subtype; | ||
2194 | err = pci_enable_device(pdev); | ||
2195 | if (err) { | ||
2196 | kfree(card); | ||
2197 | return err; | ||
2198 | } | ||
2199 | |||
2200 | printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n", | ||
2201 | m->name, pci_name(pdev)); | ||
2202 | |||
2203 | card->irq = pdev->irq; | ||
2204 | pci_set_drvdata(pdev, card); | ||
2205 | err = setup_card(card); | ||
2206 | if (err) | ||
2207 | pci_set_drvdata(pdev, NULL); | ||
2208 | return err; | ||
2209 | } | ||
2210 | |||
2211 | static void __devexit | ||
2212 | hfc_remove_pci(struct pci_dev *pdev) | ||
2213 | { | ||
2214 | struct hfc_pci *card = pci_get_drvdata(pdev); | ||
2215 | u_long flags; | ||
2216 | |||
2217 | if (card) { | ||
2218 | write_lock_irqsave(&HFClock, flags); | ||
2219 | release_card(card); | ||
2220 | write_unlock_irqrestore(&HFClock, flags); | ||
2221 | } else | ||
2222 | if (debug) | ||
2223 | printk(KERN_WARNING "%s: drvdata allready removed\n", | ||
2224 | __func__); | ||
2225 | } | ||
2226 | |||
2227 | |||
2228 | static struct pci_driver hfc_driver = { | ||
2229 | .name = "hfcpci", | ||
2230 | .probe = hfc_probe, | ||
2231 | .remove = __devexit_p(hfc_remove_pci), | ||
2232 | .id_table = hfc_ids, | ||
2233 | }; | ||
2234 | |||
2235 | static int __init | ||
2236 | HFC_init(void) | ||
2237 | { | ||
2238 | int err; | ||
2239 | |||
2240 | err = pci_register_driver(&hfc_driver); | ||
2241 | return err; | ||
2242 | } | ||
2243 | |||
2244 | static void __exit | ||
2245 | HFC_cleanup(void) | ||
2246 | { | ||
2247 | struct hfc_pci *card, *next; | ||
2248 | |||
2249 | list_for_each_entry_safe(card, next, &HFClist, list) { | ||
2250 | release_card(card); | ||
2251 | } | ||
2252 | pci_unregister_driver(&hfc_driver); | ||
2253 | } | ||
2254 | |||
2255 | module_init(HFC_init); | ||
2256 | module_exit(HFC_cleanup); | ||
diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig new file mode 100644 index 000000000000..4938355c4072 --- /dev/null +++ b/drivers/isdn/mISDN/Kconfig | |||
@@ -0,0 +1,44 @@ | |||
1 | # | ||
2 | # modularer ISDN driver | ||
3 | # | ||
4 | |||
5 | menuconfig MISDN | ||
6 | tristate "Modular ISDN driver" | ||
7 | help | ||
8 | Enable support for the modular ISDN driver. | ||
9 | |||
10 | if MISDN != n | ||
11 | |||
12 | config MISDN_DSP | ||
13 | tristate "Digital Audio Processing of transparent data" | ||
14 | depends on MISDN | ||
15 | help | ||
16 | Enable support for digital audio processing capability. | ||
17 | This module may be used for special applications that require | ||
18 | cross connecting of bchannels, conferencing, dtmf decoding | ||
19 | echo cancelation, tone generation, and Blowfish encryption and | ||
20 | decryption. | ||
21 | It may use hardware features if available. | ||
22 | E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu | ||
23 | and get more informations about this module and it's usage. | ||
24 | If unsure, say 'N'. | ||
25 | |||
26 | config MISDN_L1OIP | ||
27 | tristate "ISDN over IP tunnel" | ||
28 | depends on MISDN | ||
29 | help | ||
30 | Enable support for ISDN over IP tunnel. | ||
31 | |||
32 | It features: | ||
33 | - dynamic IP exchange, if one or both peers have dynamic IPs | ||
34 | - BRI (S0) and PRI (S2M) interface | ||
35 | - layer 1 control via network keepalive frames | ||
36 | - direct tunneling of physical interface via IP | ||
37 | |||
38 | NOTE: This protocol is called 'Layer 1 over IP' and is not | ||
39 | compatible with ISDNoIP (Agfeo) or TDMoIP. Protocol description is | ||
40 | provided in the source code. | ||
41 | |||
42 | source "drivers/isdn/hardware/mISDN/Kconfig" | ||
43 | |||
44 | endif #MISDN | ||
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile new file mode 100644 index 000000000000..1cb5e633cf75 --- /dev/null +++ b/drivers/isdn/mISDN/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the modular ISDN driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_MISDN) += mISDN_core.o | ||
6 | obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o | ||
7 | obj-$(CONFIG_MISDN_L1OIP) += l1oip.o | ||
8 | |||
9 | # multi objects | ||
10 | |||
11 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o | ||
12 | mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o | ||
13 | l1oip-objs := l1oip_core.o l1oip_codec.o | ||
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c new file mode 100644 index 000000000000..33068177b7c9 --- /dev/null +++ b/drivers/isdn/mISDN/core.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/mISDNif.h> | ||
20 | #include "core.h" | ||
21 | |||
22 | static u_int debug; | ||
23 | |||
24 | MODULE_AUTHOR("Karsten Keil"); | ||
25 | MODULE_LICENSE("GPL"); | ||
26 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
27 | |||
28 | static LIST_HEAD(devices); | ||
29 | DEFINE_RWLOCK(device_lock); | ||
30 | static u64 device_ids; | ||
31 | #define MAX_DEVICE_ID 63 | ||
32 | |||
33 | static LIST_HEAD(Bprotocols); | ||
34 | DEFINE_RWLOCK(bp_lock); | ||
35 | |||
36 | struct mISDNdevice | ||
37 | *get_mdevice(u_int id) | ||
38 | { | ||
39 | struct mISDNdevice *dev; | ||
40 | |||
41 | read_lock(&device_lock); | ||
42 | list_for_each_entry(dev, &devices, D.list) | ||
43 | if (dev->id == id) { | ||
44 | read_unlock(&device_lock); | ||
45 | return dev; | ||
46 | } | ||
47 | read_unlock(&device_lock); | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | int | ||
52 | get_mdevice_count(void) | ||
53 | { | ||
54 | struct mISDNdevice *dev; | ||
55 | int cnt = 0; | ||
56 | |||
57 | read_lock(&device_lock); | ||
58 | list_for_each_entry(dev, &devices, D.list) | ||
59 | cnt++; | ||
60 | read_unlock(&device_lock); | ||
61 | return cnt; | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | get_free_devid(void) | ||
66 | { | ||
67 | u_int i; | ||
68 | |||
69 | for (i = 0; i <= MAX_DEVICE_ID; i++) | ||
70 | if (!test_and_set_bit(i, (u_long *)&device_ids)) | ||
71 | return i; | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | int | ||
76 | mISDN_register_device(struct mISDNdevice *dev, char *name) | ||
77 | { | ||
78 | u_long flags; | ||
79 | int err; | ||
80 | |||
81 | dev->id = get_free_devid(); | ||
82 | if (dev->id < 0) | ||
83 | return -EBUSY; | ||
84 | if (name && name[0]) | ||
85 | strcpy(dev->name, name); | ||
86 | else | ||
87 | sprintf(dev->name, "mISDN%d", dev->id); | ||
88 | if (debug & DEBUG_CORE) | ||
89 | printk(KERN_DEBUG "mISDN_register %s %d\n", | ||
90 | dev->name, dev->id); | ||
91 | err = create_stack(dev); | ||
92 | if (err) | ||
93 | return err; | ||
94 | write_lock_irqsave(&device_lock, flags); | ||
95 | list_add_tail(&dev->D.list, &devices); | ||
96 | write_unlock_irqrestore(&device_lock, flags); | ||
97 | return 0; | ||
98 | } | ||
99 | EXPORT_SYMBOL(mISDN_register_device); | ||
100 | |||
101 | void | ||
102 | mISDN_unregister_device(struct mISDNdevice *dev) { | ||
103 | u_long flags; | ||
104 | |||
105 | if (debug & DEBUG_CORE) | ||
106 | printk(KERN_DEBUG "mISDN_unregister %s %d\n", | ||
107 | dev->name, dev->id); | ||
108 | write_lock_irqsave(&device_lock, flags); | ||
109 | list_del(&dev->D.list); | ||
110 | write_unlock_irqrestore(&device_lock, flags); | ||
111 | test_and_clear_bit(dev->id, (u_long *)&device_ids); | ||
112 | delete_stack(dev); | ||
113 | } | ||
114 | EXPORT_SYMBOL(mISDN_unregister_device); | ||
115 | |||
116 | u_int | ||
117 | get_all_Bprotocols(void) | ||
118 | { | ||
119 | struct Bprotocol *bp; | ||
120 | u_int m = 0; | ||
121 | |||
122 | read_lock(&bp_lock); | ||
123 | list_for_each_entry(bp, &Bprotocols, list) | ||
124 | m |= bp->Bprotocols; | ||
125 | read_unlock(&bp_lock); | ||
126 | return m; | ||
127 | } | ||
128 | |||
129 | struct Bprotocol * | ||
130 | get_Bprotocol4mask(u_int m) | ||
131 | { | ||
132 | struct Bprotocol *bp; | ||
133 | |||
134 | read_lock(&bp_lock); | ||
135 | list_for_each_entry(bp, &Bprotocols, list) | ||
136 | if (bp->Bprotocols & m) { | ||
137 | read_unlock(&bp_lock); | ||
138 | return bp; | ||
139 | } | ||
140 | read_unlock(&bp_lock); | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | struct Bprotocol * | ||
145 | get_Bprotocol4id(u_int id) | ||
146 | { | ||
147 | u_int m; | ||
148 | |||
149 | if (id < ISDN_P_B_START || id > 63) { | ||
150 | printk(KERN_WARNING "%s id not in range %d\n", | ||
151 | __func__, id); | ||
152 | return NULL; | ||
153 | } | ||
154 | m = 1 << (id & ISDN_P_B_MASK); | ||
155 | return get_Bprotocol4mask(m); | ||
156 | } | ||
157 | |||
158 | int | ||
159 | mISDN_register_Bprotocol(struct Bprotocol *bp) | ||
160 | { | ||
161 | u_long flags; | ||
162 | struct Bprotocol *old; | ||
163 | |||
164 | if (debug & DEBUG_CORE) | ||
165 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, | ||
166 | bp->name, bp->Bprotocols); | ||
167 | old = get_Bprotocol4mask(bp->Bprotocols); | ||
168 | if (old) { | ||
169 | printk(KERN_WARNING | ||
170 | "register duplicate protocol old %s/%x new %s/%x\n", | ||
171 | old->name, old->Bprotocols, bp->name, bp->Bprotocols); | ||
172 | return -EBUSY; | ||
173 | } | ||
174 | write_lock_irqsave(&bp_lock, flags); | ||
175 | list_add_tail(&bp->list, &Bprotocols); | ||
176 | write_unlock_irqrestore(&bp_lock, flags); | ||
177 | return 0; | ||
178 | } | ||
179 | EXPORT_SYMBOL(mISDN_register_Bprotocol); | ||
180 | |||
181 | void | ||
182 | mISDN_unregister_Bprotocol(struct Bprotocol *bp) | ||
183 | { | ||
184 | u_long flags; | ||
185 | |||
186 | if (debug & DEBUG_CORE) | ||
187 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, | ||
188 | bp->Bprotocols); | ||
189 | write_lock_irqsave(&bp_lock, flags); | ||
190 | list_del(&bp->list); | ||
191 | write_unlock_irqrestore(&bp_lock, flags); | ||
192 | } | ||
193 | EXPORT_SYMBOL(mISDN_unregister_Bprotocol); | ||
194 | |||
195 | int | ||
196 | mISDNInit(void) | ||
197 | { | ||
198 | int err; | ||
199 | |||
200 | printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", | ||
201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); | ||
202 | mISDN_initstack(&debug); | ||
203 | err = mISDN_inittimer(&debug); | ||
204 | if (err) | ||
205 | goto error; | ||
206 | err = l1_init(&debug); | ||
207 | if (err) { | ||
208 | mISDN_timer_cleanup(); | ||
209 | goto error; | ||
210 | } | ||
211 | err = Isdnl2_Init(&debug); | ||
212 | if (err) { | ||
213 | mISDN_timer_cleanup(); | ||
214 | l1_cleanup(); | ||
215 | goto error; | ||
216 | } | ||
217 | err = misdn_sock_init(&debug); | ||
218 | if (err) { | ||
219 | mISDN_timer_cleanup(); | ||
220 | l1_cleanup(); | ||
221 | Isdnl2_cleanup(); | ||
222 | } | ||
223 | error: | ||
224 | return err; | ||
225 | } | ||
226 | |||
227 | void mISDN_cleanup(void) | ||
228 | { | ||
229 | misdn_sock_cleanup(); | ||
230 | mISDN_timer_cleanup(); | ||
231 | l1_cleanup(); | ||
232 | Isdnl2_cleanup(); | ||
233 | |||
234 | if (!list_empty(&devices)) | ||
235 | printk(KERN_ERR "%s devices still registered\n", __func__); | ||
236 | |||
237 | if (!list_empty(&Bprotocols)) | ||
238 | printk(KERN_ERR "%s Bprotocols still registered\n", __func__); | ||
239 | printk(KERN_DEBUG "mISDNcore unloaded\n"); | ||
240 | } | ||
241 | |||
242 | module_init(mISDNInit); | ||
243 | module_exit(mISDN_cleanup); | ||
244 | |||
diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h new file mode 100644 index 000000000000..7da7233b4c1a --- /dev/null +++ b/drivers/isdn/mISDN/core.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef mISDN_CORE_H | ||
16 | #define mISDN_CORE_H | ||
17 | |||
18 | extern struct mISDNdevice *get_mdevice(u_int); | ||
19 | extern int get_mdevice_count(void); | ||
20 | |||
21 | /* stack status flag */ | ||
22 | #define mISDN_STACK_ACTION_MASK 0x0000ffff | ||
23 | #define mISDN_STACK_COMMAND_MASK 0x000f0000 | ||
24 | #define mISDN_STACK_STATUS_MASK 0xfff00000 | ||
25 | /* action bits 0-15 */ | ||
26 | #define mISDN_STACK_WORK 0 | ||
27 | #define mISDN_STACK_SETUP 1 | ||
28 | #define mISDN_STACK_CLEARING 2 | ||
29 | #define mISDN_STACK_RESTART 3 | ||
30 | #define mISDN_STACK_WAKEUP 4 | ||
31 | #define mISDN_STACK_ABORT 15 | ||
32 | /* command bits 16-19 */ | ||
33 | #define mISDN_STACK_STOPPED 16 | ||
34 | #define mISDN_STACK_INIT 17 | ||
35 | #define mISDN_STACK_THREADSTART 18 | ||
36 | /* status bits 20-31 */ | ||
37 | #define mISDN_STACK_BCHANNEL 20 | ||
38 | #define mISDN_STACK_ACTIVE 29 | ||
39 | #define mISDN_STACK_RUNNING 30 | ||
40 | #define mISDN_STACK_KILLED 31 | ||
41 | |||
42 | |||
43 | /* manager options */ | ||
44 | #define MGR_OPT_USER 24 | ||
45 | #define MGR_OPT_NETWORK 25 | ||
46 | |||
47 | extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *, | ||
48 | u_int, struct sockaddr_mISDN *); | ||
49 | extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *, | ||
50 | u_int, struct sockaddr_mISDN *); | ||
51 | extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *, | ||
52 | u_int, struct sockaddr_mISDN *); | ||
53 | |||
54 | extern int create_stack(struct mISDNdevice *); | ||
55 | extern int create_teimanager(struct mISDNdevice *); | ||
56 | extern void delete_teimanager(struct mISDNchannel *); | ||
57 | extern void delete_channel(struct mISDNchannel *); | ||
58 | extern void delete_stack(struct mISDNdevice *); | ||
59 | extern void mISDN_initstack(u_int *); | ||
60 | extern int misdn_sock_init(u_int *); | ||
61 | extern void misdn_sock_cleanup(void); | ||
62 | extern void add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
63 | extern void __add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
64 | |||
65 | extern u_int get_all_Bprotocols(void); | ||
66 | struct Bprotocol *get_Bprotocol4mask(u_int); | ||
67 | struct Bprotocol *get_Bprotocol4id(u_int); | ||
68 | |||
69 | extern int mISDN_inittimer(u_int *); | ||
70 | extern void mISDN_timer_cleanup(void); | ||
71 | |||
72 | extern int l1_init(u_int *); | ||
73 | extern void l1_cleanup(void); | ||
74 | extern int Isdnl2_Init(u_int *); | ||
75 | extern void Isdnl2_cleanup(void); | ||
76 | |||
77 | #endif | ||
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h new file mode 100644 index 000000000000..6c3fed6b8d4f --- /dev/null +++ b/drivers/isdn/mISDN/dsp.h | |||
@@ -0,0 +1,263 @@ | |||
1 | /* | ||
2 | * Audio support data for ISDN4Linux. | ||
3 | * | ||
4 | * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #define DEBUG_DSP_CTRL 0x0001 | ||
12 | #define DEBUG_DSP_CORE 0x0002 | ||
13 | #define DEBUG_DSP_DTMF 0x0004 | ||
14 | #define DEBUG_DSP_CMX 0x0010 | ||
15 | #define DEBUG_DSP_TONE 0x0020 | ||
16 | #define DEBUG_DSP_BLOWFISH 0x0040 | ||
17 | #define DEBUG_DSP_DELAY 0x0100 | ||
18 | #define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ | ||
19 | |||
20 | /* options may be: | ||
21 | * | ||
22 | * bit 0 = use ulaw instead of alaw | ||
23 | * bit 1 = enable hfc hardware accelleration for all channels | ||
24 | * | ||
25 | */ | ||
26 | #define DSP_OPT_ULAW (1<<0) | ||
27 | #define DSP_OPT_NOHARDWARE (1<<1) | ||
28 | |||
29 | #include <linux/timer.h> | ||
30 | #include <linux/workqueue.h> | ||
31 | |||
32 | #include "dsp_ecdis.h" | ||
33 | |||
34 | extern int dsp_options; | ||
35 | extern int dsp_debug; | ||
36 | extern int dsp_poll; | ||
37 | extern int dsp_tics; | ||
38 | extern spinlock_t dsp_lock; | ||
39 | extern struct work_struct dsp_workq; | ||
40 | extern u32 dsp_poll_diff; /* calculated fix-comma corrected poll value */ | ||
41 | |||
42 | /*************** | ||
43 | * audio stuff * | ||
44 | ***************/ | ||
45 | |||
46 | extern s32 dsp_audio_alaw_to_s32[256]; | ||
47 | extern s32 dsp_audio_ulaw_to_s32[256]; | ||
48 | extern s32 *dsp_audio_law_to_s32; | ||
49 | extern u8 dsp_audio_s16_to_law[65536]; | ||
50 | extern u8 dsp_audio_alaw_to_ulaw[256]; | ||
51 | extern u8 dsp_audio_mix_law[65536]; | ||
52 | extern u8 dsp_audio_seven2law[128]; | ||
53 | extern u8 dsp_audio_law2seven[256]; | ||
54 | extern void dsp_audio_generate_law_tables(void); | ||
55 | extern void dsp_audio_generate_s2law_table(void); | ||
56 | extern void dsp_audio_generate_seven(void); | ||
57 | extern void dsp_audio_generate_mix_table(void); | ||
58 | extern void dsp_audio_generate_ulaw_samples(void); | ||
59 | extern void dsp_audio_generate_volume_changes(void); | ||
60 | extern u8 dsp_silence; | ||
61 | |||
62 | |||
63 | /************* | ||
64 | * cmx stuff * | ||
65 | *************/ | ||
66 | |||
67 | #define MAX_POLL 256 /* maximum number of send-chunks */ | ||
68 | |||
69 | #define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */ | ||
70 | #define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */ | ||
71 | #define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */ | ||
72 | |||
73 | /* how many seconds will we check the lowest delay until the jitter buffer | ||
74 | is reduced by that delay */ | ||
75 | #define MAX_SECONDS_JITTER_CHECK 5 | ||
76 | |||
77 | extern struct timer_list dsp_spl_tl; | ||
78 | extern u32 dsp_spl_jiffies; | ||
79 | |||
80 | /* the structure of conferences: | ||
81 | * | ||
82 | * each conference has a unique number, given by user space. | ||
83 | * the conferences are linked in a chain. | ||
84 | * each conference has members linked in a chain. | ||
85 | * each dsplayer points to a member, each member points to a dsplayer. | ||
86 | */ | ||
87 | |||
88 | /* all members within a conference (this is linked 1:1 with the dsp) */ | ||
89 | struct dsp; | ||
90 | struct dsp_conf_member { | ||
91 | struct list_head list; | ||
92 | struct dsp *dsp; | ||
93 | }; | ||
94 | |||
95 | /* the list of all conferences */ | ||
96 | struct dsp_conf { | ||
97 | struct list_head list; | ||
98 | u32 id; | ||
99 | /* all cmx stacks with the same ID are | ||
100 | connected */ | ||
101 | struct list_head mlist; | ||
102 | int software; /* conf is processed by software */ | ||
103 | int hardware; /* conf is processed by hardware */ | ||
104 | /* note: if both unset, has only one member */ | ||
105 | }; | ||
106 | |||
107 | |||
108 | /************** | ||
109 | * DTMF stuff * | ||
110 | **************/ | ||
111 | |||
112 | #define DSP_DTMF_NPOINTS 102 | ||
113 | |||
114 | #define ECHOCAN_BUFLEN (4*128) | ||
115 | |||
116 | struct dsp_dtmf { | ||
117 | int treshold; /* above this is dtmf (square of) */ | ||
118 | int software; /* dtmf uses software decoding */ | ||
119 | int hardware; /* dtmf uses hardware decoding */ | ||
120 | int size; /* number of bytes in buffer */ | ||
121 | signed short buffer[DSP_DTMF_NPOINTS]; | ||
122 | /* buffers one full dtmf frame */ | ||
123 | u8 lastwhat, lastdigit; | ||
124 | int count; | ||
125 | u8 digits[16]; /* just the dtmf result */ | ||
126 | }; | ||
127 | |||
128 | |||
129 | /****************** | ||
130 | * pipeline stuff * | ||
131 | ******************/ | ||
132 | struct dsp_pipeline { | ||
133 | rwlock_t lock; | ||
134 | struct list_head list; | ||
135 | int inuse; | ||
136 | }; | ||
137 | |||
138 | /*************** | ||
139 | * tones stuff * | ||
140 | ***************/ | ||
141 | |||
142 | struct dsp_tone { | ||
143 | int software; /* tones are generated by software */ | ||
144 | int hardware; /* tones are generated by hardware */ | ||
145 | int tone; | ||
146 | void *pattern; | ||
147 | int count; | ||
148 | int index; | ||
149 | struct timer_list tl; | ||
150 | }; | ||
151 | |||
152 | /***************** | ||
153 | * general stuff * | ||
154 | *****************/ | ||
155 | |||
156 | struct dsp { | ||
157 | struct list_head list; | ||
158 | struct mISDNchannel ch; | ||
159 | struct mISDNchannel *up; | ||
160 | unsigned char name[64]; | ||
161 | int b_active; | ||
162 | int echo; /* echo is enabled */ | ||
163 | int rx_disabled; /* what the user wants */ | ||
164 | int rx_is_off; /* what the card is */ | ||
165 | int tx_mix; | ||
166 | struct dsp_tone tone; | ||
167 | struct dsp_dtmf dtmf; | ||
168 | int tx_volume, rx_volume; | ||
169 | |||
170 | /* queue for sending frames */ | ||
171 | struct work_struct workq; | ||
172 | struct sk_buff_head sendq; | ||
173 | int hdlc; /* if mode is hdlc */ | ||
174 | int data_pending; /* currently an unconfirmed frame */ | ||
175 | |||
176 | /* conference stuff */ | ||
177 | u32 conf_id; | ||
178 | struct dsp_conf *conf; | ||
179 | struct dsp_conf_member | ||
180 | *member; | ||
181 | |||
182 | /* buffer stuff */ | ||
183 | int rx_W; /* current write pos for data without timestamp */ | ||
184 | int rx_R; /* current read pos for transmit clock */ | ||
185 | int rx_init; /* if set, pointers will be adjusted first */ | ||
186 | int tx_W; /* current write pos for transmit data */ | ||
187 | int tx_R; /* current read pos for transmit clock */ | ||
188 | int rx_delay[MAX_SECONDS_JITTER_CHECK]; | ||
189 | int tx_delay[MAX_SECONDS_JITTER_CHECK]; | ||
190 | u8 tx_buff[CMX_BUFF_SIZE]; | ||
191 | u8 rx_buff[CMX_BUFF_SIZE]; | ||
192 | int last_tx; /* if set, we transmitted last poll interval */ | ||
193 | int cmx_delay; /* initial delay of buffers, | ||
194 | or 0 for dynamic jitter buffer */ | ||
195 | int tx_dejitter; /* if set, dejitter tx buffer */ | ||
196 | int tx_data; /* enables tx-data of CMX to upper layer */ | ||
197 | |||
198 | /* hardware stuff */ | ||
199 | struct dsp_features features; | ||
200 | int features_rx_off; /* set if rx_off is featured */ | ||
201 | int pcm_slot_rx; /* current PCM slot (or -1) */ | ||
202 | int pcm_bank_rx; | ||
203 | int pcm_slot_tx; | ||
204 | int pcm_bank_tx; | ||
205 | int hfc_conf; /* unique id of current conference (or -1) */ | ||
206 | |||
207 | /* encryption stuff */ | ||
208 | int bf_enable; | ||
209 | u32 bf_p[18]; | ||
210 | u32 bf_s[1024]; | ||
211 | int bf_crypt_pos; | ||
212 | u8 bf_data_in[9]; | ||
213 | u8 bf_crypt_out[9]; | ||
214 | int bf_decrypt_in_pos; | ||
215 | int bf_decrypt_out_pos; | ||
216 | u8 bf_crypt_inring[16]; | ||
217 | u8 bf_data_out[9]; | ||
218 | int bf_sync; | ||
219 | |||
220 | struct dsp_pipeline | ||
221 | pipeline; | ||
222 | }; | ||
223 | |||
224 | /* functions */ | ||
225 | |||
226 | extern void dsp_change_volume(struct sk_buff *skb, int volume); | ||
227 | |||
228 | extern struct list_head dsp_ilist; | ||
229 | extern struct list_head conf_ilist; | ||
230 | extern void dsp_cmx_debug(struct dsp *dsp); | ||
231 | extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp); | ||
232 | extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id); | ||
233 | extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb); | ||
234 | extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb); | ||
235 | extern void dsp_cmx_send(void *arg); | ||
236 | extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb); | ||
237 | extern int dsp_cmx_del_conf_member(struct dsp *dsp); | ||
238 | extern int dsp_cmx_del_conf(struct dsp_conf *conf); | ||
239 | |||
240 | extern void dsp_dtmf_goertzel_init(struct dsp *dsp); | ||
241 | extern void dsp_dtmf_hardware(struct dsp *dsp); | ||
242 | extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, | ||
243 | int fmt); | ||
244 | |||
245 | extern int dsp_tone(struct dsp *dsp, int tone); | ||
246 | extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len); | ||
247 | extern void dsp_tone_timeout(void *arg); | ||
248 | |||
249 | extern void dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len); | ||
250 | extern void dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len); | ||
251 | extern int dsp_bf_init(struct dsp *dsp, const u8 *key, unsigned int keylen); | ||
252 | extern void dsp_bf_cleanup(struct dsp *dsp); | ||
253 | |||
254 | extern int dsp_pipeline_module_init(void); | ||
255 | extern void dsp_pipeline_module_exit(void); | ||
256 | extern int dsp_pipeline_init(struct dsp_pipeline *pipeline); | ||
257 | extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline); | ||
258 | extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); | ||
259 | extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, | ||
260 | int len); | ||
261 | extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, | ||
262 | int len); | ||
263 | |||
diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c new file mode 100644 index 000000000000..1c2dd5694773 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_audio.c | |||
@@ -0,0 +1,434 @@ | |||
1 | /* | ||
2 | * Audio support data for mISDN_dsp. | ||
3 | * | ||
4 | * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * Rewritten by Peter | ||
6 | * | ||
7 | * This software may be used and distributed according to the terms | ||
8 | * of the GNU General Public License, incorporated herein by reference. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/mISDNif.h> | ||
14 | #include <linux/mISDNdsp.h> | ||
15 | #include "core.h" | ||
16 | #include "dsp.h" | ||
17 | |||
18 | /* ulaw[unsigned char] -> signed 16-bit */ | ||
19 | s32 dsp_audio_ulaw_to_s32[256]; | ||
20 | /* alaw[unsigned char] -> signed 16-bit */ | ||
21 | s32 dsp_audio_alaw_to_s32[256]; | ||
22 | |||
23 | s32 *dsp_audio_law_to_s32; | ||
24 | EXPORT_SYMBOL(dsp_audio_law_to_s32); | ||
25 | |||
26 | /* signed 16-bit -> law */ | ||
27 | u8 dsp_audio_s16_to_law[65536]; | ||
28 | EXPORT_SYMBOL(dsp_audio_s16_to_law); | ||
29 | |||
30 | /* alaw -> ulaw */ | ||
31 | u8 dsp_audio_alaw_to_ulaw[256]; | ||
32 | /* ulaw -> alaw */ | ||
33 | u8 dsp_audio_ulaw_to_alaw[256]; | ||
34 | u8 dsp_silence; | ||
35 | |||
36 | |||
37 | /***************************************************** | ||
38 | * generate table for conversion of s16 to alaw/ulaw * | ||
39 | *****************************************************/ | ||
40 | |||
41 | #define AMI_MASK 0x55 | ||
42 | |||
43 | static inline unsigned char linear2alaw(short int linear) | ||
44 | { | ||
45 | int mask; | ||
46 | int seg; | ||
47 | int pcm_val; | ||
48 | static int seg_end[8] = { | ||
49 | 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF | ||
50 | }; | ||
51 | |||
52 | pcm_val = linear; | ||
53 | if (pcm_val >= 0) { | ||
54 | /* Sign (7th) bit = 1 */ | ||
55 | mask = AMI_MASK | 0x80; | ||
56 | } else { | ||
57 | /* Sign bit = 0 */ | ||
58 | mask = AMI_MASK; | ||
59 | pcm_val = -pcm_val; | ||
60 | } | ||
61 | |||
62 | /* Convert the scaled magnitude to segment number. */ | ||
63 | for (seg = 0; seg < 8; seg++) { | ||
64 | if (pcm_val <= seg_end[seg]) | ||
65 | break; | ||
66 | } | ||
67 | /* Combine the sign, segment, and quantization bits. */ | ||
68 | return ((seg << 4) | | ||
69 | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; | ||
70 | } | ||
71 | |||
72 | |||
73 | static inline short int alaw2linear(unsigned char alaw) | ||
74 | { | ||
75 | int i; | ||
76 | int seg; | ||
77 | |||
78 | alaw ^= AMI_MASK; | ||
79 | i = ((alaw & 0x0F) << 4) + 8 /* rounding error */; | ||
80 | seg = (((int) alaw & 0x70) >> 4); | ||
81 | if (seg) | ||
82 | i = (i + 0x100) << (seg - 1); | ||
83 | return (short int) ((alaw & 0x80) ? i : -i); | ||
84 | } | ||
85 | |||
86 | static inline short int ulaw2linear(unsigned char ulaw) | ||
87 | { | ||
88 | short mu, e, f, y; | ||
89 | static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764}; | ||
90 | |||
91 | mu = 255 - ulaw; | ||
92 | e = (mu & 0x70) / 16; | ||
93 | f = mu & 0x0f; | ||
94 | y = f * (1 << (e + 3)); | ||
95 | y += etab[e]; | ||
96 | if (mu & 0x80) | ||
97 | y = -y; | ||
98 | return y; | ||
99 | } | ||
100 | |||
101 | #define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */ | ||
102 | |||
103 | static unsigned char linear2ulaw(short sample) | ||
104 | { | ||
105 | static int exp_lut[256] = { | ||
106 | 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, | ||
107 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | ||
108 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
109 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
110 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
111 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
112 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
113 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
114 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
115 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
116 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
117 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
118 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
119 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
120 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
121 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; | ||
122 | int sign, exponent, mantissa; | ||
123 | unsigned char ulawbyte; | ||
124 | |||
125 | /* Get the sample into sign-magnitude. */ | ||
126 | sign = (sample >> 8) & 0x80; /* set aside the sign */ | ||
127 | if (sign != 0) | ||
128 | sample = -sample; /* get magnitude */ | ||
129 | |||
130 | /* Convert from 16 bit linear to ulaw. */ | ||
131 | sample = sample + BIAS; | ||
132 | exponent = exp_lut[(sample >> 7) & 0xFF]; | ||
133 | mantissa = (sample >> (exponent + 3)) & 0x0F; | ||
134 | ulawbyte = ~(sign | (exponent << 4) | mantissa); | ||
135 | |||
136 | return ulawbyte; | ||
137 | } | ||
138 | |||
139 | static int reverse_bits(int i) | ||
140 | { | ||
141 | int z, j; | ||
142 | z = 0; | ||
143 | |||
144 | for (j = 0; j < 8; j++) { | ||
145 | if ((i & (1 << j)) != 0) | ||
146 | z |= 1 << (7 - j); | ||
147 | } | ||
148 | return z; | ||
149 | } | ||
150 | |||
151 | |||
152 | void dsp_audio_generate_law_tables(void) | ||
153 | { | ||
154 | int i; | ||
155 | for (i = 0; i < 256; i++) | ||
156 | dsp_audio_alaw_to_s32[i] = alaw2linear(reverse_bits(i)); | ||
157 | |||
158 | for (i = 0; i < 256; i++) | ||
159 | dsp_audio_ulaw_to_s32[i] = ulaw2linear(reverse_bits(i)); | ||
160 | |||
161 | for (i = 0; i < 256; i++) { | ||
162 | dsp_audio_alaw_to_ulaw[i] = | ||
163 | linear2ulaw(dsp_audio_alaw_to_s32[i]); | ||
164 | dsp_audio_ulaw_to_alaw[i] = | ||
165 | linear2alaw(dsp_audio_ulaw_to_s32[i]); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | void | ||
170 | dsp_audio_generate_s2law_table(void) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | if (dsp_options & DSP_OPT_ULAW) { | ||
175 | /* generating ulaw-table */ | ||
176 | for (i = -32768; i < 32768; i++) { | ||
177 | dsp_audio_s16_to_law[i & 0xffff] = | ||
178 | reverse_bits(linear2ulaw(i)); | ||
179 | } | ||
180 | } else { | ||
181 | /* generating alaw-table */ | ||
182 | for (i = -32768; i < 32768; i++) { | ||
183 | dsp_audio_s16_to_law[i & 0xffff] = | ||
184 | reverse_bits(linear2alaw(i)); | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | |||
190 | /* | ||
191 | * the seven bit sample is the number of every second alaw-sample ordered by | ||
192 | * aplitude. 0x00 is negative, 0x7f is positive amplitude. | ||
193 | */ | ||
194 | u8 dsp_audio_seven2law[128]; | ||
195 | u8 dsp_audio_law2seven[256]; | ||
196 | |||
197 | /******************************************************************** | ||
198 | * generate table for conversion law from/to 7-bit alaw-like sample * | ||
199 | ********************************************************************/ | ||
200 | |||
201 | void | ||
202 | dsp_audio_generate_seven(void) | ||
203 | { | ||
204 | int i, j, k; | ||
205 | u8 spl; | ||
206 | u8 sorted_alaw[256]; | ||
207 | |||
208 | /* generate alaw table, sorted by the linear value */ | ||
209 | for (i = 0; i < 256; i++) { | ||
210 | j = 0; | ||
211 | for (k = 0; k < 256; k++) { | ||
212 | if (dsp_audio_alaw_to_s32[k] | ||
213 | < dsp_audio_alaw_to_s32[i]) { | ||
214 | j++; | ||
215 | } | ||
216 | } | ||
217 | sorted_alaw[j] = i; | ||
218 | } | ||
219 | |||
220 | /* generate tabels */ | ||
221 | for (i = 0; i < 256; i++) { | ||
222 | /* spl is the source: the law-sample (converted to alaw) */ | ||
223 | spl = i; | ||
224 | if (dsp_options & DSP_OPT_ULAW) | ||
225 | spl = dsp_audio_ulaw_to_alaw[i]; | ||
226 | /* find the 7-bit-sample */ | ||
227 | for (j = 0; j < 256; j++) { | ||
228 | if (sorted_alaw[j] == spl) | ||
229 | break; | ||
230 | } | ||
231 | /* write 7-bit audio value */ | ||
232 | dsp_audio_law2seven[i] = j >> 1; | ||
233 | } | ||
234 | for (i = 0; i < 128; i++) { | ||
235 | spl = sorted_alaw[i << 1]; | ||
236 | if (dsp_options & DSP_OPT_ULAW) | ||
237 | spl = dsp_audio_alaw_to_ulaw[spl]; | ||
238 | dsp_audio_seven2law[i] = spl; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | |||
243 | /* mix 2*law -> law */ | ||
244 | u8 dsp_audio_mix_law[65536]; | ||
245 | |||
246 | /****************************************************** | ||
247 | * generate mix table to mix two law samples into one * | ||
248 | ******************************************************/ | ||
249 | |||
250 | void | ||
251 | dsp_audio_generate_mix_table(void) | ||
252 | { | ||
253 | int i, j; | ||
254 | s32 sample; | ||
255 | |||
256 | i = 0; | ||
257 | while (i < 256) { | ||
258 | j = 0; | ||
259 | while (j < 256) { | ||
260 | sample = dsp_audio_law_to_s32[i]; | ||
261 | sample += dsp_audio_law_to_s32[j]; | ||
262 | if (sample > 32767) | ||
263 | sample = 32767; | ||
264 | if (sample < -32768) | ||
265 | sample = -32768; | ||
266 | dsp_audio_mix_law[(i<<8)|j] = | ||
267 | dsp_audio_s16_to_law[sample & 0xffff]; | ||
268 | j++; | ||
269 | } | ||
270 | i++; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | /************************************* | ||
276 | * generate different volume changes * | ||
277 | *************************************/ | ||
278 | |||
279 | static u8 dsp_audio_reduce8[256]; | ||
280 | static u8 dsp_audio_reduce7[256]; | ||
281 | static u8 dsp_audio_reduce6[256]; | ||
282 | static u8 dsp_audio_reduce5[256]; | ||
283 | static u8 dsp_audio_reduce4[256]; | ||
284 | static u8 dsp_audio_reduce3[256]; | ||
285 | static u8 dsp_audio_reduce2[256]; | ||
286 | static u8 dsp_audio_reduce1[256]; | ||
287 | static u8 dsp_audio_increase1[256]; | ||
288 | static u8 dsp_audio_increase2[256]; | ||
289 | static u8 dsp_audio_increase3[256]; | ||
290 | static u8 dsp_audio_increase4[256]; | ||
291 | static u8 dsp_audio_increase5[256]; | ||
292 | static u8 dsp_audio_increase6[256]; | ||
293 | static u8 dsp_audio_increase7[256]; | ||
294 | static u8 dsp_audio_increase8[256]; | ||
295 | |||
296 | static u8 *dsp_audio_volume_change[16] = { | ||
297 | dsp_audio_reduce8, | ||
298 | dsp_audio_reduce7, | ||
299 | dsp_audio_reduce6, | ||
300 | dsp_audio_reduce5, | ||
301 | dsp_audio_reduce4, | ||
302 | dsp_audio_reduce3, | ||
303 | dsp_audio_reduce2, | ||
304 | dsp_audio_reduce1, | ||
305 | dsp_audio_increase1, | ||
306 | dsp_audio_increase2, | ||
307 | dsp_audio_increase3, | ||
308 | dsp_audio_increase4, | ||
309 | dsp_audio_increase5, | ||
310 | dsp_audio_increase6, | ||
311 | dsp_audio_increase7, | ||
312 | dsp_audio_increase8, | ||
313 | }; | ||
314 | |||
315 | void | ||
316 | dsp_audio_generate_volume_changes(void) | ||
317 | { | ||
318 | register s32 sample; | ||
319 | int i; | ||
320 | int num[] = { 110, 125, 150, 175, 200, 300, 400, 500 }; | ||
321 | int denum[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; | ||
322 | |||
323 | i = 0; | ||
324 | while (i < 256) { | ||
325 | dsp_audio_reduce8[i] = dsp_audio_s16_to_law[ | ||
326 | (dsp_audio_law_to_s32[i] * denum[7] / num[7]) & 0xffff]; | ||
327 | dsp_audio_reduce7[i] = dsp_audio_s16_to_law[ | ||
328 | (dsp_audio_law_to_s32[i] * denum[6] / num[6]) & 0xffff]; | ||
329 | dsp_audio_reduce6[i] = dsp_audio_s16_to_law[ | ||
330 | (dsp_audio_law_to_s32[i] * denum[5] / num[5]) & 0xffff]; | ||
331 | dsp_audio_reduce5[i] = dsp_audio_s16_to_law[ | ||
332 | (dsp_audio_law_to_s32[i] * denum[4] / num[4]) & 0xffff]; | ||
333 | dsp_audio_reduce4[i] = dsp_audio_s16_to_law[ | ||
334 | (dsp_audio_law_to_s32[i] * denum[3] / num[3]) & 0xffff]; | ||
335 | dsp_audio_reduce3[i] = dsp_audio_s16_to_law[ | ||
336 | (dsp_audio_law_to_s32[i] * denum[2] / num[2]) & 0xffff]; | ||
337 | dsp_audio_reduce2[i] = dsp_audio_s16_to_law[ | ||
338 | (dsp_audio_law_to_s32[i] * denum[1] / num[1]) & 0xffff]; | ||
339 | dsp_audio_reduce1[i] = dsp_audio_s16_to_law[ | ||
340 | (dsp_audio_law_to_s32[i] * denum[0] / num[0]) & 0xffff]; | ||
341 | sample = dsp_audio_law_to_s32[i] * num[0] / denum[0]; | ||
342 | if (sample < -32768) | ||
343 | sample = -32768; | ||
344 | else if (sample > 32767) | ||
345 | sample = 32767; | ||
346 | dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
347 | sample = dsp_audio_law_to_s32[i] * num[1] / denum[1]; | ||
348 | if (sample < -32768) | ||
349 | sample = -32768; | ||
350 | else if (sample > 32767) | ||
351 | sample = 32767; | ||
352 | dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
353 | sample = dsp_audio_law_to_s32[i] * num[2] / denum[2]; | ||
354 | if (sample < -32768) | ||
355 | sample = -32768; | ||
356 | else if (sample > 32767) | ||
357 | sample = 32767; | ||
358 | dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
359 | sample = dsp_audio_law_to_s32[i] * num[3] / denum[3]; | ||
360 | if (sample < -32768) | ||
361 | sample = -32768; | ||
362 | else if (sample > 32767) | ||
363 | sample = 32767; | ||
364 | dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
365 | sample = dsp_audio_law_to_s32[i] * num[4] / denum[4]; | ||
366 | if (sample < -32768) | ||
367 | sample = -32768; | ||
368 | else if (sample > 32767) | ||
369 | sample = 32767; | ||
370 | dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
371 | sample = dsp_audio_law_to_s32[i] * num[5] / denum[5]; | ||
372 | if (sample < -32768) | ||
373 | sample = -32768; | ||
374 | else if (sample > 32767) | ||
375 | sample = 32767; | ||
376 | dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
377 | sample = dsp_audio_law_to_s32[i] * num[6] / denum[6]; | ||
378 | if (sample < -32768) | ||
379 | sample = -32768; | ||
380 | else if (sample > 32767) | ||
381 | sample = 32767; | ||
382 | dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
383 | sample = dsp_audio_law_to_s32[i] * num[7] / denum[7]; | ||
384 | if (sample < -32768) | ||
385 | sample = -32768; | ||
386 | else if (sample > 32767) | ||
387 | sample = 32767; | ||
388 | dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
389 | |||
390 | i++; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | |||
395 | /************************************** | ||
396 | * change the volume of the given skb * | ||
397 | **************************************/ | ||
398 | |||
399 | /* this is a helper function for changing volume of skb. the range may be | ||
400 | * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8 | ||
401 | */ | ||
402 | void | ||
403 | dsp_change_volume(struct sk_buff *skb, int volume) | ||
404 | { | ||
405 | u8 *volume_change; | ||
406 | int i, ii; | ||
407 | u8 *p; | ||
408 | int shift; | ||
409 | |||
410 | if (volume == 0) | ||
411 | return; | ||
412 | |||
413 | /* get correct conversion table */ | ||
414 | if (volume < 0) { | ||
415 | shift = volume + 8; | ||
416 | if (shift < 0) | ||
417 | shift = 0; | ||
418 | } else { | ||
419 | shift = volume + 7; | ||
420 | if (shift > 15) | ||
421 | shift = 15; | ||
422 | } | ||
423 | volume_change = dsp_audio_volume_change[shift]; | ||
424 | i = 0; | ||
425 | ii = skb->len; | ||
426 | p = skb->data; | ||
427 | /* change volume */ | ||
428 | while (i < ii) { | ||
429 | *p = volume_change[*p]; | ||
430 | p++; | ||
431 | i++; | ||
432 | } | ||
433 | } | ||
434 | |||
diff --git a/drivers/isdn/mISDN/dsp_biquad.h b/drivers/isdn/mISDN/dsp_biquad.h new file mode 100644 index 000000000000..038191bc45f5 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_biquad.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * SpanDSP - a series of DSP components for telephony | ||
3 | * | ||
4 | * biquad.h - General telephony bi-quad section routines (currently this just | ||
5 | * handles canonic/type 2 form) | ||
6 | * | ||
7 | * Written by Steve Underwood <steveu@coppice.org> | ||
8 | * | ||
9 | * Copyright (C) 2001 Steve Underwood | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | struct biquad2_state { | ||
30 | int32_t gain; | ||
31 | int32_t a1; | ||
32 | int32_t a2; | ||
33 | int32_t b1; | ||
34 | int32_t b2; | ||
35 | |||
36 | int32_t z1; | ||
37 | int32_t z2; | ||
38 | }; | ||
39 | |||
40 | static inline void biquad2_init(struct biquad2_state *bq, | ||
41 | int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) | ||
42 | { | ||
43 | bq->gain = gain; | ||
44 | bq->a1 = a1; | ||
45 | bq->a2 = a2; | ||
46 | bq->b1 = b1; | ||
47 | bq->b2 = b2; | ||
48 | |||
49 | bq->z1 = 0; | ||
50 | bq->z2 = 0; | ||
51 | } | ||
52 | |||
53 | static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample) | ||
54 | { | ||
55 | int32_t y; | ||
56 | int32_t z0; | ||
57 | |||
58 | z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; | ||
59 | y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; | ||
60 | |||
61 | bq->z2 = bq->z1; | ||
62 | bq->z1 = z0 >> 15; | ||
63 | y >>= 15; | ||
64 | return y; | ||
65 | } | ||
diff --git a/drivers/isdn/mISDN/dsp_blowfish.c b/drivers/isdn/mISDN/dsp_blowfish.c new file mode 100644 index 000000000000..18e411e95bba --- /dev/null +++ b/drivers/isdn/mISDN/dsp_blowfish.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * Blowfish encryption/decryption for mISDN_dsp. | ||
3 | * | ||
4 | * Copyright Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/mISDNif.h> | ||
12 | #include <linux/mISDNdsp.h> | ||
13 | #include "core.h" | ||
14 | #include "dsp.h" | ||
15 | |||
16 | /* | ||
17 | * how to encode a sample stream to 64-bit blocks that will be encryped | ||
18 | * | ||
19 | * first of all, data is collected until a block of 9 samples are received. | ||
20 | * of course, a packet may have much more than 9 sample, but is may have | ||
21 | * not excacly the multiple of 9 samples. if there is a rest, the next | ||
22 | * received data will complete the block. | ||
23 | * | ||
24 | * the block is then converted to 9 uLAW samples without the least sigificant | ||
25 | * bit. the result is a 7-bit encoded sample. | ||
26 | * | ||
27 | * the samples will be reoganised to form 8 bytes of data: | ||
28 | * (5(6) means: encoded sample no. 5, bit 6) | ||
29 | * | ||
30 | * 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6) | ||
31 | * 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5) | ||
32 | * 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4) | ||
33 | * 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3) | ||
34 | * 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2) | ||
35 | * 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) | ||
36 | * 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) | ||
37 | * 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0) | ||
38 | * | ||
39 | * the missing bit 0 of the last byte is filled with some | ||
40 | * random noise, to fill all 8 bytes. | ||
41 | * | ||
42 | * the 8 bytes will be encrypted using blowfish. | ||
43 | * | ||
44 | * the result will be converted into 9 bytes. the bit 7 is used for | ||
45 | * checksumme (CS) for sync (0, 1) and for the last bit: | ||
46 | * (5(6) means: crypted byte 5, bit 6) | ||
47 | * | ||
48 | * 1 0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) | ||
49 | * 0 0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2) | ||
50 | * 0 1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3) | ||
51 | * 0 2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4) | ||
52 | * 0 3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5) | ||
53 | * CS 4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6) | ||
54 | * CS 5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7) | ||
55 | * CS 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0) | ||
56 | * 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) | ||
57 | * | ||
58 | * the checksum is used to detect transmission errors and frame drops. | ||
59 | * | ||
60 | * synchronisation of received block is done by shifting the upper bit of each | ||
61 | * byte (bit 7) to a shift register. if the rigister has the first five bits | ||
62 | * (10000), this is used to find the sync. only if sync has been found, the | ||
63 | * current block of 9 received bytes are decrypted. before that the check | ||
64 | * sum is calculated. if it is incorrect the block is dropped. | ||
65 | * this will avoid loud noise due to corrupt encrypted data. | ||
66 | * | ||
67 | * if the last block is corrupt, the current decoded block is repeated | ||
68 | * until a valid block has been received. | ||
69 | */ | ||
70 | |||
71 | /* | ||
72 | * some blowfish parts are taken from the | ||
73 | * crypto-api for faster implementation | ||
74 | */ | ||
75 | |||
76 | struct bf_ctx { | ||
77 | u32 p[18]; | ||
78 | u32 s[1024]; | ||
79 | }; | ||
80 | |||
81 | static const u32 bf_pbox[16 + 2] = { | ||
82 | 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, | ||
83 | 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, | ||
84 | 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, | ||
85 | 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, | ||
86 | 0x9216d5d9, 0x8979fb1b, | ||
87 | }; | ||
88 | |||
89 | static const u32 bf_sbox[256 * 4] = { | ||
90 | 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, | ||
91 | 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, | ||
92 | 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, | ||
93 | 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, | ||
94 | 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, | ||
95 | 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, | ||
96 | 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, | ||
97 | 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, | ||
98 | 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, | ||
99 | 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, | ||
100 | 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, | ||
101 | 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, | ||
102 | 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, | ||
103 | 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, | ||
104 | 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, | ||
105 | 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, | ||
106 | 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, | ||
107 | 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, | ||
108 | 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, | ||
109 | 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, | ||
110 | 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, | ||
111 | 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, | ||
112 | 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, | ||
113 | 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, | ||
114 | 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, | ||
115 | 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, | ||
116 | 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, | ||
117 | 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, | ||
118 | 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, | ||
119 | 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, | ||
120 | 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, | ||
121 | 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, | ||
122 | 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, | ||
123 | 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, | ||
124 | 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, | ||
125 | 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, | ||
126 | 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, | ||
127 | 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, | ||
128 | 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, | ||
129 | 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, | ||
130 | 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, | ||
131 | 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, | ||
132 | 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, | ||
133 | 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, | ||
134 | 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, | ||
135 | 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, | ||
136 | 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, | ||
137 | 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, | ||
138 | 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, | ||
139 | 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, | ||
140 | 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, | ||
141 | 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, | ||
142 | 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, | ||
143 | 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, | ||
144 | 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, | ||
145 | 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, | ||
146 | 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, | ||
147 | 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, | ||
148 | 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, | ||
149 | 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, | ||
150 | 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, | ||
151 | 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, | ||
152 | 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, | ||
153 | 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, | ||
154 | 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, | ||
155 | 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, | ||
156 | 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, | ||
157 | 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, | ||
158 | 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, | ||
159 | 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, | ||
160 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, | ||
161 | 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, | ||
162 | 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, | ||
163 | 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, | ||
164 | 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, | ||
165 | 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, | ||
166 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, | ||
167 | 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, | ||
168 | 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, | ||
169 | 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, | ||
170 | 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, | ||
171 | 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, | ||
172 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, | ||
173 | 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, | ||
174 | 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, | ||
175 | 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, | ||
176 | 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, | ||
177 | 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, | ||
178 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, | ||
179 | 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, | ||
180 | 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, | ||
181 | 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, | ||
182 | 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, | ||
183 | 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, | ||
184 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, | ||
185 | 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, | ||
186 | 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, | ||
187 | 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, | ||
188 | 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, | ||
189 | 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, | ||
190 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, | ||
191 | 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, | ||
192 | 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, | ||
193 | 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, | ||
194 | 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, | ||
195 | 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, | ||
196 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, | ||
197 | 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, | ||
198 | 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, | ||
199 | 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, | ||
200 | 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, | ||
201 | 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, | ||
202 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, | ||
203 | 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, | ||
204 | 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, | ||
205 | 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, | ||
206 | 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, | ||
207 | 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, | ||
208 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, | ||
209 | 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, | ||
210 | 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, | ||
211 | 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, | ||
212 | 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, | ||
213 | 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, | ||
214 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, | ||
215 | 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, | ||
216 | 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, | ||
217 | 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, | ||
218 | 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, | ||
219 | 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, | ||
220 | 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, | ||
221 | 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, | ||
222 | 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, | ||
223 | 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, | ||
224 | 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, | ||
225 | 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, | ||
226 | 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, | ||
227 | 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, | ||
228 | 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, | ||
229 | 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, | ||
230 | 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, | ||
231 | 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, | ||
232 | 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, | ||
233 | 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, | ||
234 | 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, | ||
235 | 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, | ||
236 | 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, | ||
237 | 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, | ||
238 | 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, | ||
239 | 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, | ||
240 | 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, | ||
241 | 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, | ||
242 | 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, | ||
243 | 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, | ||
244 | 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, | ||
245 | 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, | ||
246 | 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, | ||
247 | 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, | ||
248 | 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, | ||
249 | 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, | ||
250 | 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, | ||
251 | 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, | ||
252 | 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, | ||
253 | 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, | ||
254 | 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, | ||
255 | 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, | ||
256 | 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, | ||
257 | 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, | ||
258 | 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, | ||
259 | 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, | ||
260 | 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, | ||
261 | 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, | ||
262 | 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, | ||
263 | 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, | ||
264 | 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, | ||
265 | 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, | ||
266 | 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, | ||
267 | 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, | ||
268 | 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, | ||
269 | 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, | ||
270 | 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, | ||
271 | 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, | ||
272 | 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, | ||
273 | 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, | ||
274 | 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, | ||
275 | 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, | ||
276 | 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, | ||
277 | 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, | ||
278 | 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, | ||
279 | 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, | ||
280 | 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, | ||
281 | 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, | ||
282 | 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, | ||
283 | 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, | ||
284 | 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, | ||
285 | 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, | ||
286 | 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, | ||
287 | 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, | ||
288 | 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, | ||
289 | 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, | ||
290 | 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, | ||
291 | 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, | ||
292 | 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, | ||
293 | 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, | ||
294 | 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, | ||
295 | 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, | ||
296 | 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, | ||
297 | 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, | ||
298 | 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, | ||
299 | 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, | ||
300 | 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, | ||
301 | 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, | ||
302 | 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, | ||
303 | 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, | ||
304 | 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, | ||
305 | 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, | ||
306 | 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, | ||
307 | 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, | ||
308 | 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, | ||
309 | 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, | ||
310 | 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, | ||
311 | 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, | ||
312 | 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, | ||
313 | 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, | ||
314 | 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, | ||
315 | 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, | ||
316 | 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, | ||
317 | 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, | ||
318 | 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, | ||
319 | 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, | ||
320 | 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, | ||
321 | 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, | ||
322 | 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, | ||
323 | 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, | ||
324 | 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, | ||
325 | 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, | ||
326 | 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, | ||
327 | 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, | ||
328 | 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, | ||
329 | 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, | ||
330 | 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, | ||
331 | 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, | ||
332 | 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, | ||
333 | 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, | ||
334 | 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, | ||
335 | 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, | ||
336 | 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, | ||
337 | 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, | ||
338 | 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, | ||
339 | 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, | ||
340 | 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, | ||
341 | 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, | ||
342 | 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, | ||
343 | 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, | ||
344 | 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, | ||
345 | 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, | ||
346 | }; | ||
347 | |||
348 | /* | ||
349 | * Round loop unrolling macros, S is a pointer to a S-Box array | ||
350 | * organized in 4 unsigned longs at a row. | ||
351 | */ | ||
352 | #define GET32_3(x) (((x) & 0xff)) | ||
353 | #define GET32_2(x) (((x) >> (8)) & (0xff)) | ||
354 | #define GET32_1(x) (((x) >> (16)) & (0xff)) | ||
355 | #define GET32_0(x) (((x) >> (24)) & (0xff)) | ||
356 | |||
357 | #define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ | ||
358 | S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) | ||
359 | |||
360 | #define EROUND(a, b, n) do { b ^= P[n]; a ^= bf_F(b); } while (0) | ||
361 | #define DROUND(a, b, n) do { a ^= bf_F(b); b ^= P[n]; } while (0) | ||
362 | |||
363 | |||
364 | /* | ||
365 | * encrypt isdn data frame | ||
366 | * every block with 9 samples is encrypted | ||
367 | */ | ||
368 | void | ||
369 | dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len) | ||
370 | { | ||
371 | int i = 0, j = dsp->bf_crypt_pos; | ||
372 | u8 *bf_data_in = dsp->bf_data_in; | ||
373 | u8 *bf_crypt_out = dsp->bf_crypt_out; | ||
374 | u32 *P = dsp->bf_p; | ||
375 | u32 *S = dsp->bf_s; | ||
376 | u32 yl, yr; | ||
377 | u32 cs; | ||
378 | u8 nibble; | ||
379 | |||
380 | while (i < len) { | ||
381 | /* collect a block of 9 samples */ | ||
382 | if (j < 9) { | ||
383 | bf_data_in[j] = *data; | ||
384 | *data++ = bf_crypt_out[j++]; | ||
385 | i++; | ||
386 | continue; | ||
387 | } | ||
388 | j = 0; | ||
389 | /* transcode 9 samples xlaw to 8 bytes */ | ||
390 | yl = dsp_audio_law2seven[bf_data_in[0]]; | ||
391 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[1]]; | ||
392 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[2]]; | ||
393 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[3]]; | ||
394 | nibble = dsp_audio_law2seven[bf_data_in[4]]; | ||
395 | yr = nibble; | ||
396 | yl = (yl<<4) | (nibble>>3); | ||
397 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[5]]; | ||
398 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[6]]; | ||
399 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[7]]; | ||
400 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[8]]; | ||
401 | yr = (yr<<1) | (bf_data_in[0] & 1); | ||
402 | |||
403 | /* fill unused bit with random noise of audio input */ | ||
404 | /* encrypt */ | ||
405 | |||
406 | EROUND(yr, yl, 0); | ||
407 | EROUND(yl, yr, 1); | ||
408 | EROUND(yr, yl, 2); | ||
409 | EROUND(yl, yr, 3); | ||
410 | EROUND(yr, yl, 4); | ||
411 | EROUND(yl, yr, 5); | ||
412 | EROUND(yr, yl, 6); | ||
413 | EROUND(yl, yr, 7); | ||
414 | EROUND(yr, yl, 8); | ||
415 | EROUND(yl, yr, 9); | ||
416 | EROUND(yr, yl, 10); | ||
417 | EROUND(yl, yr, 11); | ||
418 | EROUND(yr, yl, 12); | ||
419 | EROUND(yl, yr, 13); | ||
420 | EROUND(yr, yl, 14); | ||
421 | EROUND(yl, yr, 15); | ||
422 | yl ^= P[16]; | ||
423 | yr ^= P[17]; | ||
424 | |||
425 | /* calculate 3-bit checksumme */ | ||
426 | cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) | ||
427 | ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) | ||
428 | ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) | ||
429 | ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) | ||
430 | ^ (yr>>28) ^ (yr>>31); | ||
431 | |||
432 | /* | ||
433 | * transcode 8 crypted bytes to 9 data bytes with sync | ||
434 | * and checksum information | ||
435 | */ | ||
436 | bf_crypt_out[0] = (yl>>25) | 0x80; | ||
437 | bf_crypt_out[1] = (yl>>18) & 0x7f; | ||
438 | bf_crypt_out[2] = (yl>>11) & 0x7f; | ||
439 | bf_crypt_out[3] = (yl>>4) & 0x7f; | ||
440 | bf_crypt_out[4] = ((yl<<3) & 0x78) | ((yr>>29) & 0x07); | ||
441 | bf_crypt_out[5] = ((yr>>22) & 0x7f) | ((cs<<5) & 0x80); | ||
442 | bf_crypt_out[6] = ((yr>>15) & 0x7f) | ((cs<<6) & 0x80); | ||
443 | bf_crypt_out[7] = ((yr>>8) & 0x7f) | (cs<<7); | ||
444 | bf_crypt_out[8] = yr; | ||
445 | } | ||
446 | |||
447 | /* write current count */ | ||
448 | dsp->bf_crypt_pos = j; | ||
449 | |||
450 | } | ||
451 | |||
452 | |||
453 | /* | ||
454 | * decrypt isdn data frame | ||
455 | * every block with 9 bytes is decrypted | ||
456 | */ | ||
457 | void | ||
458 | dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len) | ||
459 | { | ||
460 | int i = 0; | ||
461 | u8 j = dsp->bf_decrypt_in_pos; | ||
462 | u8 k = dsp->bf_decrypt_out_pos; | ||
463 | u8 *bf_crypt_inring = dsp->bf_crypt_inring; | ||
464 | u8 *bf_data_out = dsp->bf_data_out; | ||
465 | u16 sync = dsp->bf_sync; | ||
466 | u32 *P = dsp->bf_p; | ||
467 | u32 *S = dsp->bf_s; | ||
468 | u32 yl, yr; | ||
469 | u8 nibble; | ||
470 | u8 cs, cs0, cs1, cs2; | ||
471 | |||
472 | while (i < len) { | ||
473 | /* | ||
474 | * shift upper bit and rotate data to buffer ring | ||
475 | * send current decrypted data | ||
476 | */ | ||
477 | sync = (sync<<1) | ((*data)>>7); | ||
478 | bf_crypt_inring[j++ & 15] = *data; | ||
479 | *data++ = bf_data_out[k++]; | ||
480 | i++; | ||
481 | if (k == 9) | ||
482 | k = 0; /* repeat if no sync has been found */ | ||
483 | /* check if not in sync */ | ||
484 | if ((sync&0x1f0) != 0x100) | ||
485 | continue; | ||
486 | j -= 9; | ||
487 | /* transcode receive data to 64 bit block of encrypted data */ | ||
488 | yl = bf_crypt_inring[j++ & 15]; | ||
489 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
490 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
491 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
492 | nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
493 | yr = nibble; | ||
494 | yl = (yl<<4) | (nibble>>3); | ||
495 | cs2 = bf_crypt_inring[j++ & 15]; | ||
496 | yr = (yr<<7) | (cs2 & 0x7f); | ||
497 | cs1 = bf_crypt_inring[j++ & 15]; | ||
498 | yr = (yr<<7) | (cs1 & 0x7f); | ||
499 | cs0 = bf_crypt_inring[j++ & 15]; | ||
500 | yr = (yr<<7) | (cs0 & 0x7f); | ||
501 | yr = (yr<<8) | bf_crypt_inring[j++ & 15]; | ||
502 | |||
503 | /* calculate 3-bit checksumme */ | ||
504 | cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) | ||
505 | ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) | ||
506 | ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) | ||
507 | ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) | ||
508 | ^ (yr>>28) ^ (yr>>31); | ||
509 | |||
510 | /* check if frame is valid */ | ||
511 | if ((cs&0x7) != (((cs2>>5)&4) | ((cs1>>6)&2) | (cs0 >> 7))) { | ||
512 | if (dsp_debug & DEBUG_DSP_BLOWFISH) | ||
513 | printk(KERN_DEBUG | ||
514 | "DSP BLOWFISH: received corrupt frame, " | ||
515 | "checksumme is not correct\n"); | ||
516 | continue; | ||
517 | } | ||
518 | |||
519 | /* decrypt */ | ||
520 | yr ^= P[17]; | ||
521 | yl ^= P[16]; | ||
522 | DROUND(yl, yr, 15); | ||
523 | DROUND(yr, yl, 14); | ||
524 | DROUND(yl, yr, 13); | ||
525 | DROUND(yr, yl, 12); | ||
526 | DROUND(yl, yr, 11); | ||
527 | DROUND(yr, yl, 10); | ||
528 | DROUND(yl, yr, 9); | ||
529 | DROUND(yr, yl, 8); | ||
530 | DROUND(yl, yr, 7); | ||
531 | DROUND(yr, yl, 6); | ||
532 | DROUND(yl, yr, 5); | ||
533 | DROUND(yr, yl, 4); | ||
534 | DROUND(yl, yr, 3); | ||
535 | DROUND(yr, yl, 2); | ||
536 | DROUND(yl, yr, 1); | ||
537 | DROUND(yr, yl, 0); | ||
538 | |||
539 | /* transcode 8 crypted bytes to 9 sample bytes */ | ||
540 | bf_data_out[0] = dsp_audio_seven2law[(yl>>25) & 0x7f]; | ||
541 | bf_data_out[1] = dsp_audio_seven2law[(yl>>18) & 0x7f]; | ||
542 | bf_data_out[2] = dsp_audio_seven2law[(yl>>11) & 0x7f]; | ||
543 | bf_data_out[3] = dsp_audio_seven2law[(yl>>4) & 0x7f]; | ||
544 | bf_data_out[4] = dsp_audio_seven2law[((yl<<3) & 0x78) | | ||
545 | ((yr>>29) & 0x07)]; | ||
546 | |||
547 | bf_data_out[5] = dsp_audio_seven2law[(yr>>22) & 0x7f]; | ||
548 | bf_data_out[6] = dsp_audio_seven2law[(yr>>15) & 0x7f]; | ||
549 | bf_data_out[7] = dsp_audio_seven2law[(yr>>8) & 0x7f]; | ||
550 | bf_data_out[8] = dsp_audio_seven2law[(yr>>1) & 0x7f]; | ||
551 | k = 0; /* start with new decoded frame */ | ||
552 | } | ||
553 | |||
554 | /* write current count and sync */ | ||
555 | dsp->bf_decrypt_in_pos = j; | ||
556 | dsp->bf_decrypt_out_pos = k; | ||
557 | dsp->bf_sync = sync; | ||
558 | } | ||
559 | |||
560 | |||
561 | /* used to encrypt S and P boxes */ | ||
562 | static inline void | ||
563 | encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src) | ||
564 | { | ||
565 | u32 yl = src[0]; | ||
566 | u32 yr = src[1]; | ||
567 | |||
568 | EROUND(yr, yl, 0); | ||
569 | EROUND(yl, yr, 1); | ||
570 | EROUND(yr, yl, 2); | ||
571 | EROUND(yl, yr, 3); | ||
572 | EROUND(yr, yl, 4); | ||
573 | EROUND(yl, yr, 5); | ||
574 | EROUND(yr, yl, 6); | ||
575 | EROUND(yl, yr, 7); | ||
576 | EROUND(yr, yl, 8); | ||
577 | EROUND(yl, yr, 9); | ||
578 | EROUND(yr, yl, 10); | ||
579 | EROUND(yl, yr, 11); | ||
580 | EROUND(yr, yl, 12); | ||
581 | EROUND(yl, yr, 13); | ||
582 | EROUND(yr, yl, 14); | ||
583 | EROUND(yl, yr, 15); | ||
584 | |||
585 | yl ^= P[16]; | ||
586 | yr ^= P[17]; | ||
587 | |||
588 | dst[0] = yr; | ||
589 | dst[1] = yl; | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * initialize the dsp for encryption and decryption using the same key | ||
594 | * Calculates the blowfish S and P boxes for encryption and decryption. | ||
595 | * The margin of keylen must be 4-56 bytes. | ||
596 | * returns 0 if ok. | ||
597 | */ | ||
598 | int | ||
599 | dsp_bf_init(struct dsp *dsp, const u8 *key, uint keylen) | ||
600 | { | ||
601 | short i, j, count; | ||
602 | u32 data[2], temp; | ||
603 | u32 *P = (u32 *)dsp->bf_p; | ||
604 | u32 *S = (u32 *)dsp->bf_s; | ||
605 | |||
606 | if (keylen < 4 || keylen > 56) | ||
607 | return 1; | ||
608 | |||
609 | /* Set dsp states */ | ||
610 | i = 0; | ||
611 | while (i < 9) { | ||
612 | dsp->bf_crypt_out[i] = 0xff; | ||
613 | dsp->bf_data_out[i] = dsp_silence; | ||
614 | i++; | ||
615 | } | ||
616 | dsp->bf_crypt_pos = 0; | ||
617 | dsp->bf_decrypt_in_pos = 0; | ||
618 | dsp->bf_decrypt_out_pos = 0; | ||
619 | dsp->bf_sync = 0x1ff; | ||
620 | dsp->bf_enable = 1; | ||
621 | |||
622 | /* Copy the initialization s-boxes */ | ||
623 | for (i = 0, count = 0; i < 256; i++) | ||
624 | for (j = 0; j < 4; j++, count++) | ||
625 | S[count] = bf_sbox[count]; | ||
626 | |||
627 | /* Set the p-boxes */ | ||
628 | for (i = 0; i < 16 + 2; i++) | ||
629 | P[i] = bf_pbox[i]; | ||
630 | |||
631 | /* Actual subkey generation */ | ||
632 | for (j = 0, i = 0; i < 16 + 2; i++) { | ||
633 | temp = (((u32)key[j] << 24) | | ||
634 | ((u32)key[(j + 1) % keylen] << 16) | | ||
635 | ((u32)key[(j + 2) % keylen] << 8) | | ||
636 | ((u32)key[(j + 3) % keylen])); | ||
637 | |||
638 | P[i] = P[i] ^ temp; | ||
639 | j = (j + 4) % keylen; | ||
640 | } | ||
641 | |||
642 | data[0] = 0x00000000; | ||
643 | data[1] = 0x00000000; | ||
644 | |||
645 | for (i = 0; i < 16 + 2; i += 2) { | ||
646 | encrypt_block(P, S, data, data); | ||
647 | |||
648 | P[i] = data[0]; | ||
649 | P[i + 1] = data[1]; | ||
650 | } | ||
651 | |||
652 | for (i = 0; i < 4; i++) { | ||
653 | for (j = 0, count = i * 256; j < 256; j += 2, count += 2) { | ||
654 | encrypt_block(P, S, data, data); | ||
655 | |||
656 | S[count] = data[0]; | ||
657 | S[count + 1] = data[1]; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | |||
665 | /* | ||
666 | * turn encryption off | ||
667 | */ | ||
668 | void | ||
669 | dsp_bf_cleanup(struct dsp *dsp) | ||
670 | { | ||
671 | dsp->bf_enable = 0; | ||
672 | } | ||
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c new file mode 100644 index 000000000000..e92b1ba4b45e --- /dev/null +++ b/drivers/isdn/mISDN/dsp_cmx.c | |||
@@ -0,0 +1,1886 @@ | |||
1 | /* | ||
2 | * Audio crossconnecting/conferrencing (hardware level). | ||
3 | * | ||
4 | * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * The process of adding and removing parties to/from a conference: | ||
13 | * | ||
14 | * There is a chain of struct dsp_conf which has one or more members in a chain | ||
15 | * of struct dsp_conf_member. | ||
16 | * | ||
17 | * After a party is added, the conference is checked for hardware capability. | ||
18 | * Also if a party is removed, the conference is checked again. | ||
19 | * | ||
20 | * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect | ||
21 | * 1-n = hardware-conference. The n will give the conference number. | ||
22 | * | ||
23 | * Depending on the change after removal or insertion of a party, hardware | ||
24 | * commands are given. | ||
25 | * | ||
26 | * The current solution is stored within the struct dsp_conf entry. | ||
27 | */ | ||
28 | |||
29 | /* | ||
30 | * HOW THE CMX WORKS: | ||
31 | * | ||
32 | * There are 3 types of interaction: One member is alone, in this case only | ||
33 | * data flow from upper to lower layer is done. | ||
34 | * Two members will also exchange their data so they are crossconnected. | ||
35 | * Three or more members will be added in a conference and will hear each | ||
36 | * other but will not receive their own speech (echo) if not enabled. | ||
37 | * | ||
38 | * Features of CMX are: | ||
39 | * - Crossconnecting or even conference, if more than two members are together. | ||
40 | * - Force mixing of transmit data with other crossconnect/conference members. | ||
41 | * - Echo generation to benchmark the delay of audio processing. | ||
42 | * - Use hardware to minimize cpu load, disable FIFO load and minimize delay. | ||
43 | * - Dejittering and clock generation. | ||
44 | * | ||
45 | * There are 2 buffers: | ||
46 | * | ||
47 | * | ||
48 | * RX-Buffer | ||
49 | * R W | ||
50 | * | | | ||
51 | * ----------------+-------------+------------------- | ||
52 | * | ||
53 | * The rx-buffer is a ring buffer used to store the received data for each | ||
54 | * individual member. This is only the case if data needs to be dejittered | ||
55 | * or in case of a conference where different clocks require reclocking. | ||
56 | * The transmit-clock (R) will read the buffer. | ||
57 | * If the clock overruns the write-pointer, we will have a buffer underrun. | ||
58 | * If the write pointer always has a certain distance from the transmit- | ||
59 | * clock, we will have a delay. The delay will dynamically be increased and | ||
60 | * reduced. | ||
61 | * | ||
62 | * | ||
63 | * TX-Buffer | ||
64 | * R W | ||
65 | * | | | ||
66 | * -----------------+--------+----------------------- | ||
67 | * | ||
68 | * The tx-buffer is a ring buffer to queue the transmit data from user space | ||
69 | * until it will be mixed or sent. There are two pointers, R and W. If the write | ||
70 | * pointer W would reach or overrun R, the buffer would overrun. In this case | ||
71 | * (some) data is dropped so that it will not overrun. | ||
72 | * Additionally a dynamic dejittering can be enabled. this allows data from | ||
73 | * user space that have jitter and different clock source. | ||
74 | * | ||
75 | * | ||
76 | * Clock: | ||
77 | * | ||
78 | * A Clock is not required, if the data source has exactly one clock. In this | ||
79 | * case the data source is forwarded to the destination. | ||
80 | * | ||
81 | * A Clock is required, because the data source | ||
82 | * - has multiple clocks. | ||
83 | * - has no usable clock due to jitter or packet loss (VoIP). | ||
84 | * In this case the system's clock is used. The clock resolution depends on | ||
85 | * the jiffie resolution. | ||
86 | * | ||
87 | * If a member joins a conference: | ||
88 | * | ||
89 | * - If a member joins, its rx_buff is set to silence and change read pointer | ||
90 | * to transmit clock. | ||
91 | * | ||
92 | * The procedure of received data from card is explained in cmx_receive. | ||
93 | * The procedure of received data from user space is explained in cmx_transmit. | ||
94 | * The procedure of transmit data to card is cmx_send. | ||
95 | * | ||
96 | * | ||
97 | * Interaction with other features: | ||
98 | * | ||
99 | * DTMF: | ||
100 | * DTMF decoding is done before the data is crossconnected. | ||
101 | * | ||
102 | * Volume change: | ||
103 | * Changing rx-volume is done before the data is crossconnected. The tx-volume | ||
104 | * must be changed whenever data is transmitted to the card by the cmx. | ||
105 | * | ||
106 | * Tones: | ||
107 | * If a tone is enabled, it will be processed whenever data is transmitted to | ||
108 | * the card. It will replace the tx-data from the user space. | ||
109 | * If tones are generated by hardware, this conference member is removed for | ||
110 | * this time. | ||
111 | * | ||
112 | * Disable rx-data: | ||
113 | * If cmx is realized in hardware, rx data will be disabled if requested by | ||
114 | * the upper layer. If dtmf decoding is done by software and enabled, rx data | ||
115 | * will not be diabled but blocked to the upper layer. | ||
116 | * | ||
117 | * HFC conference engine: | ||
118 | * If it is possible to realize all features using hardware, hardware will be | ||
119 | * used if not forbidden by control command. Disabling rx-data provides | ||
120 | * absolutely traffic free audio processing. (except for the quick 1-frame | ||
121 | * upload of a tone loop, only once for a new tone) | ||
122 | * | ||
123 | */ | ||
124 | |||
125 | /* delay.h is required for hw_lock.h */ | ||
126 | |||
127 | #include <linux/delay.h> | ||
128 | #include <linux/mISDNif.h> | ||
129 | #include <linux/mISDNdsp.h> | ||
130 | #include "core.h" | ||
131 | #include "dsp.h" | ||
132 | /* | ||
133 | * debugging of multi party conference, | ||
134 | * by using conference even with two members | ||
135 | */ | ||
136 | |||
137 | /* #define CMX_CONF_DEBUG */ | ||
138 | |||
139 | /*#define CMX_DEBUG * massive read/write pointer output */ | ||
140 | /*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ | ||
141 | |||
142 | static inline int | ||
143 | count_list_member(struct list_head *head) | ||
144 | { | ||
145 | int cnt = 0; | ||
146 | struct list_head *m; | ||
147 | |||
148 | list_for_each(m, head) | ||
149 | cnt++; | ||
150 | return cnt; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * debug cmx memory structure | ||
155 | */ | ||
156 | void | ||
157 | dsp_cmx_debug(struct dsp *dsp) | ||
158 | { | ||
159 | struct dsp_conf *conf; | ||
160 | struct dsp_conf_member *member; | ||
161 | struct dsp *odsp; | ||
162 | |||
163 | printk(KERN_DEBUG "-----Current DSP\n"); | ||
164 | list_for_each_entry(odsp, &dsp_ilist, list) { | ||
165 | printk(KERN_DEBUG "* %s echo=%d txmix=%d", | ||
166 | odsp->name, odsp->echo, odsp->tx_mix); | ||
167 | if (odsp->conf) | ||
168 | printk(" (Conf %d)", odsp->conf->id); | ||
169 | if (dsp == odsp) | ||
170 | printk(" *this*"); | ||
171 | printk("\n"); | ||
172 | } | ||
173 | printk(KERN_DEBUG "-----Current Conf:\n"); | ||
174 | list_for_each_entry(conf, &conf_ilist, list) { | ||
175 | printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf); | ||
176 | list_for_each_entry(member, &conf->mlist, list) { | ||
177 | printk(KERN_DEBUG | ||
178 | " - member = %s (slot_tx %d, bank_tx %d, " | ||
179 | "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", | ||
180 | member->dsp->name, member->dsp->pcm_slot_tx, | ||
181 | member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, | ||
182 | member->dsp->pcm_bank_rx, member->dsp->hfc_conf, | ||
183 | (member->dsp == dsp) ? " *this*" : ""); | ||
184 | } | ||
185 | } | ||
186 | printk(KERN_DEBUG "-----end\n"); | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * search conference | ||
191 | */ | ||
192 | static struct dsp_conf * | ||
193 | dsp_cmx_search_conf(u32 id) | ||
194 | { | ||
195 | struct dsp_conf *conf; | ||
196 | |||
197 | if (!id) { | ||
198 | printk(KERN_WARNING "%s: conference ID is 0.\n", __func__); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | /* search conference */ | ||
203 | list_for_each_entry(conf, &conf_ilist, list) | ||
204 | if (conf->id == id) | ||
205 | return conf; | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | |||
211 | /* | ||
212 | * add member to conference | ||
213 | */ | ||
214 | static int | ||
215 | dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) | ||
216 | { | ||
217 | struct dsp_conf_member *member; | ||
218 | |||
219 | if (!conf || !dsp) { | ||
220 | printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | if (dsp->member) { | ||
224 | printk(KERN_WARNING "%s: dsp is already member in a conf.\n", | ||
225 | __func__); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | if (dsp->conf) { | ||
230 | printk(KERN_WARNING "%s: dsp is already in a conf.\n", | ||
231 | __func__); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); | ||
236 | if (!member) { | ||
237 | printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n"); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | member->dsp = dsp; | ||
241 | /* clear rx buffer */ | ||
242 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
243 | dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */ | ||
244 | dsp->rx_W = 0; | ||
245 | dsp->rx_R = 0; | ||
246 | |||
247 | list_add_tail(&member->list, &conf->mlist); | ||
248 | |||
249 | dsp->conf = conf; | ||
250 | dsp->member = member; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | |||
256 | /* | ||
257 | * del member from conference | ||
258 | */ | ||
259 | int | ||
260 | dsp_cmx_del_conf_member(struct dsp *dsp) | ||
261 | { | ||
262 | struct dsp_conf_member *member; | ||
263 | |||
264 | if (!dsp) { | ||
265 | printk(KERN_WARNING "%s: dsp is 0.\n", | ||
266 | __func__); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | |||
270 | if (!dsp->conf) { | ||
271 | printk(KERN_WARNING "%s: dsp is not in a conf.\n", | ||
272 | __func__); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | if (list_empty(&dsp->conf->mlist)) { | ||
277 | printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", | ||
278 | __func__); | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | |||
282 | /* find us in conf */ | ||
283 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
284 | if (member->dsp == dsp) { | ||
285 | list_del(&member->list); | ||
286 | dsp->conf = NULL; | ||
287 | dsp->member = NULL; | ||
288 | kfree(member); | ||
289 | return 0; | ||
290 | } | ||
291 | } | ||
292 | printk(KERN_WARNING | ||
293 | "%s: dsp is not present in its own conf_meber list.\n", | ||
294 | __func__); | ||
295 | |||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | |||
300 | /* | ||
301 | * new conference | ||
302 | */ | ||
303 | static struct dsp_conf | ||
304 | *dsp_cmx_new_conf(u32 id) | ||
305 | { | ||
306 | struct dsp_conf *conf; | ||
307 | |||
308 | if (!id) { | ||
309 | printk(KERN_WARNING "%s: id is 0.\n", | ||
310 | __func__); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); | ||
315 | if (!conf) { | ||
316 | printk(KERN_ERR "kmalloc struct dsp_conf failed\n"); | ||
317 | return NULL; | ||
318 | } | ||
319 | INIT_LIST_HEAD(&conf->mlist); | ||
320 | conf->id = id; | ||
321 | |||
322 | list_add_tail(&conf->list, &conf_ilist); | ||
323 | |||
324 | return conf; | ||
325 | } | ||
326 | |||
327 | |||
328 | /* | ||
329 | * del conference | ||
330 | */ | ||
331 | int | ||
332 | dsp_cmx_del_conf(struct dsp_conf *conf) | ||
333 | { | ||
334 | if (!conf) { | ||
335 | printk(KERN_WARNING "%s: conf is null.\n", | ||
336 | __func__); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | if (!list_empty(&conf->mlist)) { | ||
341 | printk(KERN_WARNING "%s: conf not empty.\n", | ||
342 | __func__); | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | list_del(&conf->list); | ||
346 | kfree(conf); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | |||
352 | /* | ||
353 | * send HW message to hfc card | ||
354 | */ | ||
355 | static void | ||
356 | dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2, | ||
357 | u32 param3, u32 param4) | ||
358 | { | ||
359 | struct mISDN_ctrl_req cq; | ||
360 | |||
361 | memset(&cq, 0, sizeof(cq)); | ||
362 | cq.op = message; | ||
363 | cq.p1 = param1 | (param2 << 8); | ||
364 | cq.p2 = param3 | (param4 << 8); | ||
365 | if (dsp->ch.peer) | ||
366 | dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq); | ||
367 | } | ||
368 | |||
369 | |||
370 | /* | ||
371 | * do hardware update and set the software/hardware flag | ||
372 | * | ||
373 | * either a conference or a dsp instance can be given | ||
374 | * if only dsp instance is given, the instance is not associated with a conf | ||
375 | * and therefore removed. if a conference is given, the dsp is expected to | ||
376 | * be member of that conference. | ||
377 | */ | ||
378 | void | ||
379 | dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) | ||
380 | { | ||
381 | struct dsp_conf_member *member, *nextm; | ||
382 | struct dsp *finddsp; | ||
383 | int memb = 0, i, ii, i1, i2; | ||
384 | int freeunits[8]; | ||
385 | u_char freeslots[256]; | ||
386 | int same_hfc = -1, same_pcm = -1, current_conf = -1, | ||
387 | all_conf = 1; | ||
388 | |||
389 | /* dsp gets updated (no conf) */ | ||
390 | if (!conf) { | ||
391 | if (!dsp) | ||
392 | return; | ||
393 | if (dsp_debug & DEBUG_DSP_CMX) | ||
394 | printk(KERN_DEBUG "%s checking dsp %s\n", | ||
395 | __func__, dsp->name); | ||
396 | one_member: | ||
397 | /* remove HFC conference if enabled */ | ||
398 | if (dsp->hfc_conf >= 0) { | ||
399 | if (dsp_debug & DEBUG_DSP_CMX) | ||
400 | printk(KERN_DEBUG | ||
401 | "%s removing %s from HFC conf %d " | ||
402 | "because dsp is split\n", __func__, | ||
403 | dsp->name, dsp->hfc_conf); | ||
404 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT, | ||
405 | 0, 0, 0, 0); | ||
406 | dsp->hfc_conf = -1; | ||
407 | } | ||
408 | /* process hw echo */ | ||
409 | if (dsp->features.pcm_banks < 1) | ||
410 | return; | ||
411 | if (!dsp->echo) { | ||
412 | /* NO ECHO: remove PCM slot if assigned */ | ||
413 | if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { | ||
414 | if (dsp_debug & DEBUG_DSP_CMX) | ||
415 | printk(KERN_DEBUG "%s removing %s from" | ||
416 | " PCM slot %d (TX) %d (RX) because" | ||
417 | " dsp is split (no echo)\n", | ||
418 | __func__, dsp->name, | ||
419 | dsp->pcm_slot_tx, dsp->pcm_slot_rx); | ||
420 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC, | ||
421 | 0, 0, 0, 0); | ||
422 | dsp->pcm_slot_tx = -1; | ||
423 | dsp->pcm_bank_tx = -1; | ||
424 | dsp->pcm_slot_rx = -1; | ||
425 | dsp->pcm_bank_rx = -1; | ||
426 | } | ||
427 | return; | ||
428 | } | ||
429 | /* ECHO: already echo */ | ||
430 | if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && | ||
431 | dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) | ||
432 | return; | ||
433 | /* ECHO: if slot already assigned */ | ||
434 | if (dsp->pcm_slot_tx >= 0) { | ||
435 | dsp->pcm_slot_rx = dsp->pcm_slot_tx; | ||
436 | dsp->pcm_bank_tx = 2; /* 2 means loop */ | ||
437 | dsp->pcm_bank_rx = 2; | ||
438 | if (dsp_debug & DEBUG_DSP_CMX) | ||
439 | printk(KERN_DEBUG | ||
440 | "%s refresh %s for echo using slot %d\n", | ||
441 | __func__, dsp->name, | ||
442 | dsp->pcm_slot_tx); | ||
443 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
444 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | ||
445 | return; | ||
446 | } | ||
447 | /* ECHO: find slot */ | ||
448 | dsp->pcm_slot_tx = -1; | ||
449 | dsp->pcm_slot_rx = -1; | ||
450 | memset(freeslots, 1, sizeof(freeslots)); | ||
451 | list_for_each_entry(finddsp, &dsp_ilist, list) { | ||
452 | if (finddsp->features.pcm_id == dsp->features.pcm_id) { | ||
453 | if (finddsp->pcm_slot_rx >= 0 && | ||
454 | finddsp->pcm_slot_rx < sizeof(freeslots)) | ||
455 | freeslots[finddsp->pcm_slot_tx] = 0; | ||
456 | if (finddsp->pcm_slot_tx >= 0 && | ||
457 | finddsp->pcm_slot_tx < sizeof(freeslots)) | ||
458 | freeslots[finddsp->pcm_slot_rx] = 0; | ||
459 | } | ||
460 | } | ||
461 | i = 0; | ||
462 | ii = dsp->features.pcm_slots; | ||
463 | while (i < ii) { | ||
464 | if (freeslots[i]) | ||
465 | break; | ||
466 | i++; | ||
467 | } | ||
468 | if (i == ii) { | ||
469 | if (dsp_debug & DEBUG_DSP_CMX) | ||
470 | printk(KERN_DEBUG | ||
471 | "%s no slot available for echo\n", | ||
472 | __func__); | ||
473 | /* no more slots available */ | ||
474 | return; | ||
475 | } | ||
476 | /* assign free slot */ | ||
477 | dsp->pcm_slot_tx = i; | ||
478 | dsp->pcm_slot_rx = i; | ||
479 | dsp->pcm_bank_tx = 2; /* loop */ | ||
480 | dsp->pcm_bank_rx = 2; | ||
481 | if (dsp_debug & DEBUG_DSP_CMX) | ||
482 | printk(KERN_DEBUG | ||
483 | "%s assign echo for %s using slot %d\n", | ||
484 | __func__, dsp->name, dsp->pcm_slot_tx); | ||
485 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
486 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | ||
487 | return; | ||
488 | } | ||
489 | |||
490 | /* conf gets updated (all members) */ | ||
491 | if (dsp_debug & DEBUG_DSP_CMX) | ||
492 | printk(KERN_DEBUG "%s checking conference %d\n", | ||
493 | __func__, conf->id); | ||
494 | |||
495 | if (list_empty(&conf->mlist)) { | ||
496 | printk(KERN_ERR "%s: conference whithout members\n", | ||
497 | __func__); | ||
498 | return; | ||
499 | } | ||
500 | member = list_entry(conf->mlist.next, struct dsp_conf_member, list); | ||
501 | same_hfc = member->dsp->features.hfc_id; | ||
502 | same_pcm = member->dsp->features.pcm_id; | ||
503 | /* check all members in our conference */ | ||
504 | list_for_each_entry(member, &conf->mlist, list) { | ||
505 | /* check if member uses mixing */ | ||
506 | if (member->dsp->tx_mix) { | ||
507 | if (dsp_debug & DEBUG_DSP_CMX) | ||
508 | printk(KERN_DEBUG | ||
509 | "%s dsp %s cannot form a conf, because " | ||
510 | "tx_mix is turned on\n", __func__, | ||
511 | member->dsp->name); | ||
512 | conf_software: | ||
513 | list_for_each_entry(member, &conf->mlist, list) { | ||
514 | dsp = member->dsp; | ||
515 | /* remove HFC conference if enabled */ | ||
516 | if (dsp->hfc_conf >= 0) { | ||
517 | if (dsp_debug & DEBUG_DSP_CMX) | ||
518 | printk(KERN_DEBUG | ||
519 | "%s removing %s from HFC " | ||
520 | "conf %d because not " | ||
521 | "possible with hardware\n", | ||
522 | __func__, | ||
523 | dsp->name, | ||
524 | dsp->hfc_conf); | ||
525 | dsp_cmx_hw_message(dsp, | ||
526 | MISDN_CTRL_HFC_CONF_SPLIT, | ||
527 | 0, 0, 0, 0); | ||
528 | dsp->hfc_conf = -1; | ||
529 | } | ||
530 | /* remove PCM slot if assigned */ | ||
531 | if (dsp->pcm_slot_tx >= 0 || | ||
532 | dsp->pcm_slot_rx >= 0) { | ||
533 | if (dsp_debug & DEBUG_DSP_CMX) | ||
534 | printk(KERN_DEBUG "%s removing " | ||
535 | "%s from PCM slot %d (TX)" | ||
536 | " slot %d (RX) because not" | ||
537 | " possible with hardware\n", | ||
538 | __func__, | ||
539 | dsp->name, | ||
540 | dsp->pcm_slot_tx, | ||
541 | dsp->pcm_slot_rx); | ||
542 | dsp_cmx_hw_message(dsp, | ||
543 | MISDN_CTRL_HFC_PCM_DISC, | ||
544 | 0, 0, 0, 0); | ||
545 | dsp->pcm_slot_tx = -1; | ||
546 | dsp->pcm_bank_tx = -1; | ||
547 | dsp->pcm_slot_rx = -1; | ||
548 | dsp->pcm_bank_rx = -1; | ||
549 | } | ||
550 | } | ||
551 | conf->hardware = 0; | ||
552 | conf->software = 1; | ||
553 | return; | ||
554 | } | ||
555 | /* check if member has echo turned on */ | ||
556 | if (member->dsp->echo) { | ||
557 | if (dsp_debug & DEBUG_DSP_CMX) | ||
558 | printk(KERN_DEBUG | ||
559 | "%s dsp %s cannot form a conf, because " | ||
560 | "echo is turned on\n", __func__, | ||
561 | member->dsp->name); | ||
562 | goto conf_software; | ||
563 | } | ||
564 | /* check if member has tx_mix turned on */ | ||
565 | if (member->dsp->tx_mix) { | ||
566 | if (dsp_debug & DEBUG_DSP_CMX) | ||
567 | printk(KERN_DEBUG | ||
568 | "%s dsp %s cannot form a conf, because " | ||
569 | "tx_mix is turned on\n", | ||
570 | __func__, member->dsp->name); | ||
571 | goto conf_software; | ||
572 | } | ||
573 | /* check if member changes volume at an not suppoted level */ | ||
574 | if (member->dsp->tx_volume) { | ||
575 | if (dsp_debug & DEBUG_DSP_CMX) | ||
576 | printk(KERN_DEBUG | ||
577 | "%s dsp %s cannot form a conf, because " | ||
578 | "tx_volume is changed\n", | ||
579 | __func__, member->dsp->name); | ||
580 | goto conf_software; | ||
581 | } | ||
582 | if (member->dsp->rx_volume) { | ||
583 | if (dsp_debug & DEBUG_DSP_CMX) | ||
584 | printk(KERN_DEBUG | ||
585 | "%s dsp %s cannot form a conf, because " | ||
586 | "rx_volume is changed\n", | ||
587 | __func__, member->dsp->name); | ||
588 | goto conf_software; | ||
589 | } | ||
590 | /* check if tx-data turned on */ | ||
591 | if (member->dsp->tx_data) { | ||
592 | if (dsp_debug & DEBUG_DSP_CMX) | ||
593 | printk(KERN_DEBUG | ||
594 | "%s dsp %s cannot form a conf, because " | ||
595 | "tx_data is turned on\n", | ||
596 | __func__, member->dsp->name); | ||
597 | goto conf_software; | ||
598 | } | ||
599 | /* check if pipeline exists */ | ||
600 | if (member->dsp->pipeline.inuse) { | ||
601 | if (dsp_debug & DEBUG_DSP_CMX) | ||
602 | printk(KERN_DEBUG | ||
603 | "%s dsp %s cannot form a conf, because " | ||
604 | "pipeline exists\n", __func__, | ||
605 | member->dsp->name); | ||
606 | goto conf_software; | ||
607 | } | ||
608 | /* check if encryption is enabled */ | ||
609 | if (member->dsp->bf_enable) { | ||
610 | if (dsp_debug & DEBUG_DSP_CMX) | ||
611 | printk(KERN_DEBUG "%s dsp %s cannot form a " | ||
612 | "conf, because encryption is enabled\n", | ||
613 | __func__, member->dsp->name); | ||
614 | goto conf_software; | ||
615 | } | ||
616 | /* check if member is on a card with PCM support */ | ||
617 | if (member->dsp->features.pcm_id < 0) { | ||
618 | if (dsp_debug & DEBUG_DSP_CMX) | ||
619 | printk(KERN_DEBUG | ||
620 | "%s dsp %s cannot form a conf, because " | ||
621 | "dsp has no PCM bus\n", | ||
622 | __func__, member->dsp->name); | ||
623 | goto conf_software; | ||
624 | } | ||
625 | /* check if relations are on the same PCM bus */ | ||
626 | if (member->dsp->features.pcm_id != same_pcm) { | ||
627 | if (dsp_debug & DEBUG_DSP_CMX) | ||
628 | printk(KERN_DEBUG | ||
629 | "%s dsp %s cannot form a conf, because " | ||
630 | "dsp is on a different PCM bus than the " | ||
631 | "first dsp\n", | ||
632 | __func__, member->dsp->name); | ||
633 | goto conf_software; | ||
634 | } | ||
635 | /* determine if members are on the same hfc chip */ | ||
636 | if (same_hfc != member->dsp->features.hfc_id) | ||
637 | same_hfc = -1; | ||
638 | /* if there are members already in a conference */ | ||
639 | if (current_conf < 0 && member->dsp->hfc_conf >= 0) | ||
640 | current_conf = member->dsp->hfc_conf; | ||
641 | /* if any member is not in a conference */ | ||
642 | if (member->dsp->hfc_conf < 0) | ||
643 | all_conf = 0; | ||
644 | |||
645 | memb++; | ||
646 | } | ||
647 | |||
648 | /* if no member, this is an error */ | ||
649 | if (memb < 1) | ||
650 | return; | ||
651 | |||
652 | /* one member */ | ||
653 | if (memb == 1) { | ||
654 | if (dsp_debug & DEBUG_DSP_CMX) | ||
655 | printk(KERN_DEBUG | ||
656 | "%s conf %d cannot form a HW conference, " | ||
657 | "because dsp is alone\n", __func__, conf->id); | ||
658 | conf->hardware = 0; | ||
659 | conf->software = 0; | ||
660 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
661 | list); | ||
662 | dsp = member->dsp; | ||
663 | goto one_member; | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * ok, now we are sure that all members are on the same pcm. | ||
668 | * now we will see if we have only two members, so we can do | ||
669 | * crossconnections, which don't have any limitations. | ||
670 | */ | ||
671 | |||
672 | /* if we have only two members */ | ||
673 | if (memb == 2) { | ||
674 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
675 | list); | ||
676 | nextm = list_entry(member->list.next, struct dsp_conf_member, | ||
677 | list); | ||
678 | /* remove HFC conference if enabled */ | ||
679 | if (member->dsp->hfc_conf >= 0) { | ||
680 | if (dsp_debug & DEBUG_DSP_CMX) | ||
681 | printk(KERN_DEBUG | ||
682 | "%s removing %s from HFC conf %d because " | ||
683 | "two parties require only a PCM slot\n", | ||
684 | __func__, member->dsp->name, | ||
685 | member->dsp->hfc_conf); | ||
686 | dsp_cmx_hw_message(member->dsp, | ||
687 | MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); | ||
688 | member->dsp->hfc_conf = -1; | ||
689 | } | ||
690 | if (nextm->dsp->hfc_conf >= 0) { | ||
691 | if (dsp_debug & DEBUG_DSP_CMX) | ||
692 | printk(KERN_DEBUG | ||
693 | "%s removing %s from HFC conf %d because " | ||
694 | "two parties require only a PCM slot\n", | ||
695 | __func__, nextm->dsp->name, | ||
696 | nextm->dsp->hfc_conf); | ||
697 | dsp_cmx_hw_message(nextm->dsp, | ||
698 | MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); | ||
699 | nextm->dsp->hfc_conf = -1; | ||
700 | } | ||
701 | /* if members have two banks (and not on the same chip) */ | ||
702 | if (member->dsp->features.pcm_banks > 1 && | ||
703 | nextm->dsp->features.pcm_banks > 1 && | ||
704 | member->dsp->features.hfc_id != | ||
705 | nextm->dsp->features.hfc_id) { | ||
706 | /* if both members have same slots with crossed banks */ | ||
707 | if (member->dsp->pcm_slot_tx >= 0 && | ||
708 | member->dsp->pcm_slot_rx >= 0 && | ||
709 | nextm->dsp->pcm_slot_tx >= 0 && | ||
710 | nextm->dsp->pcm_slot_rx >= 0 && | ||
711 | nextm->dsp->pcm_slot_tx == | ||
712 | member->dsp->pcm_slot_rx && | ||
713 | nextm->dsp->pcm_slot_rx == | ||
714 | member->dsp->pcm_slot_tx && | ||
715 | nextm->dsp->pcm_slot_tx == | ||
716 | member->dsp->pcm_slot_tx && | ||
717 | member->dsp->pcm_bank_tx != | ||
718 | member->dsp->pcm_bank_rx && | ||
719 | nextm->dsp->pcm_bank_tx != | ||
720 | nextm->dsp->pcm_bank_rx) { | ||
721 | /* all members have same slot */ | ||
722 | if (dsp_debug & DEBUG_DSP_CMX) | ||
723 | printk(KERN_DEBUG | ||
724 | "%s dsp %s & %s stay joined on " | ||
725 | "PCM slot %d bank %d (TX) bank %d " | ||
726 | "(RX) (on different chips)\n", | ||
727 | __func__, | ||
728 | member->dsp->name, | ||
729 | nextm->dsp->name, | ||
730 | member->dsp->pcm_slot_tx, | ||
731 | member->dsp->pcm_bank_tx, | ||
732 | member->dsp->pcm_bank_rx); | ||
733 | conf->hardware = 0; | ||
734 | conf->software = 1; | ||
735 | return; | ||
736 | } | ||
737 | /* find a new slot */ | ||
738 | memset(freeslots, 1, sizeof(freeslots)); | ||
739 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
740 | if (dsp != member->dsp && | ||
741 | dsp != nextm->dsp && | ||
742 | member->dsp->features.pcm_id == | ||
743 | dsp->features.pcm_id) { | ||
744 | if (dsp->pcm_slot_rx >= 0 && | ||
745 | dsp->pcm_slot_rx < | ||
746 | sizeof(freeslots)) | ||
747 | freeslots[dsp->pcm_slot_tx] = 0; | ||
748 | if (dsp->pcm_slot_tx >= 0 && | ||
749 | dsp->pcm_slot_tx < | ||
750 | sizeof(freeslots)) | ||
751 | freeslots[dsp->pcm_slot_rx] = 0; | ||
752 | } | ||
753 | } | ||
754 | i = 0; | ||
755 | ii = member->dsp->features.pcm_slots; | ||
756 | while (i < ii) { | ||
757 | if (freeslots[i]) | ||
758 | break; | ||
759 | i++; | ||
760 | } | ||
761 | if (i == ii) { | ||
762 | if (dsp_debug & DEBUG_DSP_CMX) | ||
763 | printk(KERN_DEBUG | ||
764 | "%s no slot available for " | ||
765 | "%s & %s\n", __func__, | ||
766 | member->dsp->name, | ||
767 | nextm->dsp->name); | ||
768 | /* no more slots available */ | ||
769 | goto conf_software; | ||
770 | } | ||
771 | /* assign free slot */ | ||
772 | member->dsp->pcm_slot_tx = i; | ||
773 | member->dsp->pcm_slot_rx = i; | ||
774 | nextm->dsp->pcm_slot_tx = i; | ||
775 | nextm->dsp->pcm_slot_rx = i; | ||
776 | member->dsp->pcm_bank_rx = 0; | ||
777 | member->dsp->pcm_bank_tx = 1; | ||
778 | nextm->dsp->pcm_bank_rx = 1; | ||
779 | nextm->dsp->pcm_bank_tx = 0; | ||
780 | if (dsp_debug & DEBUG_DSP_CMX) | ||
781 | printk(KERN_DEBUG | ||
782 | "%s adding %s & %s to new PCM slot %d " | ||
783 | "(TX and RX on different chips) because " | ||
784 | "both members have not same slots\n", | ||
785 | __func__, | ||
786 | member->dsp->name, | ||
787 | nextm->dsp->name, | ||
788 | member->dsp->pcm_slot_tx); | ||
789 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
790 | member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, | ||
791 | member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); | ||
792 | dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
793 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | ||
794 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | ||
795 | conf->hardware = 1; | ||
796 | conf->software = 0; | ||
797 | return; | ||
798 | /* if members have one bank (or on the same chip) */ | ||
799 | } else { | ||
800 | /* if both members have different crossed slots */ | ||
801 | if (member->dsp->pcm_slot_tx >= 0 && | ||
802 | member->dsp->pcm_slot_rx >= 0 && | ||
803 | nextm->dsp->pcm_slot_tx >= 0 && | ||
804 | nextm->dsp->pcm_slot_rx >= 0 && | ||
805 | nextm->dsp->pcm_slot_tx == | ||
806 | member->dsp->pcm_slot_rx && | ||
807 | nextm->dsp->pcm_slot_rx == | ||
808 | member->dsp->pcm_slot_tx && | ||
809 | member->dsp->pcm_slot_tx != | ||
810 | member->dsp->pcm_slot_rx && | ||
811 | member->dsp->pcm_bank_tx == 0 && | ||
812 | member->dsp->pcm_bank_rx == 0 && | ||
813 | nextm->dsp->pcm_bank_tx == 0 && | ||
814 | nextm->dsp->pcm_bank_rx == 0) { | ||
815 | /* all members have same slot */ | ||
816 | if (dsp_debug & DEBUG_DSP_CMX) | ||
817 | printk(KERN_DEBUG | ||
818 | "%s dsp %s & %s stay joined on PCM " | ||
819 | "slot %d (TX) %d (RX) on same chip " | ||
820 | "or one bank PCM)\n", __func__, | ||
821 | member->dsp->name, | ||
822 | nextm->dsp->name, | ||
823 | member->dsp->pcm_slot_tx, | ||
824 | member->dsp->pcm_slot_rx); | ||
825 | conf->hardware = 0; | ||
826 | conf->software = 1; | ||
827 | return; | ||
828 | } | ||
829 | /* find two new slot */ | ||
830 | memset(freeslots, 1, sizeof(freeslots)); | ||
831 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
832 | if (dsp != member->dsp && | ||
833 | dsp != nextm->dsp && | ||
834 | member->dsp->features.pcm_id == | ||
835 | dsp->features.pcm_id) { | ||
836 | if (dsp->pcm_slot_rx >= 0 && | ||
837 | dsp->pcm_slot_rx < | ||
838 | sizeof(freeslots)) | ||
839 | freeslots[dsp->pcm_slot_tx] = 0; | ||
840 | if (dsp->pcm_slot_tx >= 0 && | ||
841 | dsp->pcm_slot_tx < | ||
842 | sizeof(freeslots)) | ||
843 | freeslots[dsp->pcm_slot_rx] = 0; | ||
844 | } | ||
845 | } | ||
846 | i1 = 0; | ||
847 | ii = member->dsp->features.pcm_slots; | ||
848 | while (i1 < ii) { | ||
849 | if (freeslots[i1]) | ||
850 | break; | ||
851 | i1++; | ||
852 | } | ||
853 | if (i1 == ii) { | ||
854 | if (dsp_debug & DEBUG_DSP_CMX) | ||
855 | printk(KERN_DEBUG | ||
856 | "%s no slot available " | ||
857 | "for %s & %s\n", __func__, | ||
858 | member->dsp->name, | ||
859 | nextm->dsp->name); | ||
860 | /* no more slots available */ | ||
861 | goto conf_software; | ||
862 | } | ||
863 | i2 = i1+1; | ||
864 | while (i2 < ii) { | ||
865 | if (freeslots[i2]) | ||
866 | break; | ||
867 | i2++; | ||
868 | } | ||
869 | if (i2 == ii) { | ||
870 | if (dsp_debug & DEBUG_DSP_CMX) | ||
871 | printk(KERN_DEBUG | ||
872 | "%s no slot available " | ||
873 | "for %s & %s\n", | ||
874 | __func__, | ||
875 | member->dsp->name, | ||
876 | nextm->dsp->name); | ||
877 | /* no more slots available */ | ||
878 | goto conf_software; | ||
879 | } | ||
880 | /* assign free slots */ | ||
881 | member->dsp->pcm_slot_tx = i1; | ||
882 | member->dsp->pcm_slot_rx = i2; | ||
883 | nextm->dsp->pcm_slot_tx = i2; | ||
884 | nextm->dsp->pcm_slot_rx = i1; | ||
885 | member->dsp->pcm_bank_rx = 0; | ||
886 | member->dsp->pcm_bank_tx = 0; | ||
887 | nextm->dsp->pcm_bank_rx = 0; | ||
888 | nextm->dsp->pcm_bank_tx = 0; | ||
889 | if (dsp_debug & DEBUG_DSP_CMX) | ||
890 | printk(KERN_DEBUG | ||
891 | "%s adding %s & %s to new PCM slot %d " | ||
892 | "(TX) %d (RX) on same chip or one bank " | ||
893 | "PCM, because both members have not " | ||
894 | "crossed slots\n", __func__, | ||
895 | member->dsp->name, | ||
896 | nextm->dsp->name, | ||
897 | member->dsp->pcm_slot_tx, | ||
898 | member->dsp->pcm_slot_rx); | ||
899 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
900 | member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, | ||
901 | member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); | ||
902 | dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
903 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | ||
904 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | ||
905 | conf->hardware = 1; | ||
906 | conf->software = 0; | ||
907 | return; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | /* | ||
912 | * if we have more than two, we may check if we have a conference | ||
913 | * unit available on the chip. also all members must be on the same | ||
914 | */ | ||
915 | |||
916 | /* if not the same HFC chip */ | ||
917 | if (same_hfc < 0) { | ||
918 | if (dsp_debug & DEBUG_DSP_CMX) | ||
919 | printk(KERN_DEBUG | ||
920 | "%s conference %d cannot be formed, because " | ||
921 | "members are on different chips or not " | ||
922 | "on HFC chip\n", | ||
923 | __func__, conf->id); | ||
924 | goto conf_software; | ||
925 | } | ||
926 | |||
927 | /* for more than two members.. */ | ||
928 | |||
929 | /* in case of hdlc, we change to software */ | ||
930 | if (dsp->hdlc) | ||
931 | goto conf_software; | ||
932 | |||
933 | /* if all members already have the same conference */ | ||
934 | if (all_conf) | ||
935 | return; | ||
936 | |||
937 | /* | ||
938 | * if there is an existing conference, but not all members have joined | ||
939 | */ | ||
940 | if (current_conf >= 0) { | ||
941 | join_members: | ||
942 | list_for_each_entry(member, &conf->mlist, list) { | ||
943 | /* join to current conference */ | ||
944 | if (member->dsp->hfc_conf == current_conf) | ||
945 | continue; | ||
946 | /* get a free timeslot first */ | ||
947 | memset(freeslots, 1, sizeof(freeslots)); | ||
948 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
949 | /* | ||
950 | * not checking current member, because | ||
951 | * slot will be overwritten. | ||
952 | */ | ||
953 | if ( | ||
954 | dsp != member->dsp && | ||
955 | /* dsp must be on the same PCM */ | ||
956 | member->dsp->features.pcm_id == | ||
957 | dsp->features.pcm_id) { | ||
958 | /* dsp must be on a slot */ | ||
959 | if (dsp->pcm_slot_tx >= 0 && | ||
960 | dsp->pcm_slot_tx < | ||
961 | sizeof(freeslots)) | ||
962 | freeslots[dsp->pcm_slot_tx] = 0; | ||
963 | if (dsp->pcm_slot_rx >= 0 && | ||
964 | dsp->pcm_slot_rx < | ||
965 | sizeof(freeslots)) | ||
966 | freeslots[dsp->pcm_slot_rx] = 0; | ||
967 | } | ||
968 | } | ||
969 | i = 0; | ||
970 | ii = member->dsp->features.pcm_slots; | ||
971 | while (i < ii) { | ||
972 | if (freeslots[i]) | ||
973 | break; | ||
974 | i++; | ||
975 | } | ||
976 | if (i == ii) { | ||
977 | /* no more slots available */ | ||
978 | if (dsp_debug & DEBUG_DSP_CMX) | ||
979 | printk(KERN_DEBUG | ||
980 | "%s conference %d cannot be formed," | ||
981 | " because no slot free\n", | ||
982 | __func__, conf->id); | ||
983 | goto conf_software; | ||
984 | } | ||
985 | if (dsp_debug & DEBUG_DSP_CMX) | ||
986 | printk(KERN_DEBUG | ||
987 | "%s changing dsp %s to HW conference " | ||
988 | "%d slot %d\n", __func__, | ||
989 | member->dsp->name, current_conf, i); | ||
990 | /* assign free slot & set PCM & join conf */ | ||
991 | member->dsp->pcm_slot_tx = i; | ||
992 | member->dsp->pcm_slot_rx = i; | ||
993 | member->dsp->pcm_bank_tx = 2; /* loop */ | ||
994 | member->dsp->pcm_bank_rx = 2; | ||
995 | member->dsp->hfc_conf = current_conf; | ||
996 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
997 | i, 2, i, 2); | ||
998 | dsp_cmx_hw_message(member->dsp, | ||
999 | MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); | ||
1000 | } | ||
1001 | return; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
1005 | * no member is in a conference yet, so we find a free one | ||
1006 | */ | ||
1007 | memset(freeunits, 1, sizeof(freeunits)); | ||
1008 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
1009 | /* dsp must be on the same chip */ | ||
1010 | if (dsp->features.hfc_id == same_hfc && | ||
1011 | /* dsp must have joined a HW conference */ | ||
1012 | dsp->hfc_conf >= 0 && | ||
1013 | /* slot must be within range */ | ||
1014 | dsp->hfc_conf < 8) | ||
1015 | freeunits[dsp->hfc_conf] = 0; | ||
1016 | } | ||
1017 | i = 0; | ||
1018 | ii = 8; | ||
1019 | while (i < ii) { | ||
1020 | if (freeunits[i]) | ||
1021 | break; | ||
1022 | i++; | ||
1023 | } | ||
1024 | if (i == ii) { | ||
1025 | /* no more conferences available */ | ||
1026 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1027 | printk(KERN_DEBUG | ||
1028 | "%s conference %d cannot be formed, because " | ||
1029 | "no conference number free\n", | ||
1030 | __func__, conf->id); | ||
1031 | goto conf_software; | ||
1032 | } | ||
1033 | /* join all members */ | ||
1034 | current_conf = i; | ||
1035 | goto join_members; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | /* | ||
1040 | * conf_id != 0: join or change conference | ||
1041 | * conf_id == 0: split from conference if not already | ||
1042 | */ | ||
1043 | int | ||
1044 | dsp_cmx_conf(struct dsp *dsp, u32 conf_id) | ||
1045 | { | ||
1046 | int err; | ||
1047 | struct dsp_conf *conf; | ||
1048 | struct dsp_conf_member *member; | ||
1049 | |||
1050 | /* if conference doesn't change */ | ||
1051 | if (dsp->conf_id == conf_id) | ||
1052 | return 0; | ||
1053 | |||
1054 | /* first remove us from current conf */ | ||
1055 | if (dsp->conf_id) { | ||
1056 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1057 | printk(KERN_DEBUG "removing us from conference %d\n", | ||
1058 | dsp->conf->id); | ||
1059 | /* remove us from conf */ | ||
1060 | conf = dsp->conf; | ||
1061 | err = dsp_cmx_del_conf_member(dsp); | ||
1062 | if (err) | ||
1063 | return err; | ||
1064 | dsp->conf_id = 0; | ||
1065 | |||
1066 | /* update hardware */ | ||
1067 | dsp_cmx_hardware(NULL, dsp); | ||
1068 | |||
1069 | /* conf now empty? */ | ||
1070 | if (list_empty(&conf->mlist)) { | ||
1071 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1072 | printk(KERN_DEBUG | ||
1073 | "conference is empty, so we remove it.\n"); | ||
1074 | err = dsp_cmx_del_conf(conf); | ||
1075 | if (err) | ||
1076 | return err; | ||
1077 | } else { | ||
1078 | /* update members left on conf */ | ||
1079 | dsp_cmx_hardware(conf, NULL); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | /* if split */ | ||
1084 | if (!conf_id) | ||
1085 | return 0; | ||
1086 | |||
1087 | /* now add us to conf */ | ||
1088 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1089 | printk(KERN_DEBUG "searching conference %d\n", | ||
1090 | conf_id); | ||
1091 | conf = dsp_cmx_search_conf(conf_id); | ||
1092 | if (!conf) { | ||
1093 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1094 | printk(KERN_DEBUG | ||
1095 | "conference doesn't exist yet, creating.\n"); | ||
1096 | /* the conference doesn't exist, so we create */ | ||
1097 | conf = dsp_cmx_new_conf(conf_id); | ||
1098 | if (!conf) | ||
1099 | return -EINVAL; | ||
1100 | } else if (!list_empty(&conf->mlist)) { | ||
1101 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
1102 | list); | ||
1103 | if (dsp->hdlc && !member->dsp->hdlc) { | ||
1104 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1105 | printk(KERN_DEBUG | ||
1106 | "cannot join transparent conference.\n"); | ||
1107 | return -EINVAL; | ||
1108 | } | ||
1109 | if (!dsp->hdlc && member->dsp->hdlc) { | ||
1110 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1111 | printk(KERN_DEBUG | ||
1112 | "cannot join hdlc conference.\n"); | ||
1113 | return -EINVAL; | ||
1114 | } | ||
1115 | } | ||
1116 | /* add conference member */ | ||
1117 | err = dsp_cmx_add_conf_member(dsp, conf); | ||
1118 | if (err) | ||
1119 | return err; | ||
1120 | dsp->conf_id = conf_id; | ||
1121 | |||
1122 | /* if we are alone, we do nothing! */ | ||
1123 | if (list_empty(&conf->mlist)) { | ||
1124 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1125 | printk(KERN_DEBUG | ||
1126 | "we are alone in this conference, so exit.\n"); | ||
1127 | /* update hardware */ | ||
1128 | dsp_cmx_hardware(NULL, dsp); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | /* update members on conf */ | ||
1133 | dsp_cmx_hardware(conf, NULL); | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | /* | ||
1140 | * audio data is received from card | ||
1141 | */ | ||
1142 | void | ||
1143 | dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) | ||
1144 | { | ||
1145 | u8 *d, *p; | ||
1146 | int len = skb->len; | ||
1147 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1148 | int w, i, ii; | ||
1149 | |||
1150 | /* check if we have sompen */ | ||
1151 | if (len < 1) | ||
1152 | return; | ||
1153 | |||
1154 | /* half of the buffer should be larger than maximum packet size */ | ||
1155 | if (len >= CMX_BUFF_HALF) { | ||
1156 | printk(KERN_ERR | ||
1157 | "%s line %d: packet from card is too large (%d bytes). " | ||
1158 | "please make card send smaller packets OR increase " | ||
1159 | "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); | ||
1160 | return; | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * initialize pointers if not already - | ||
1165 | * also add delay if requested by PH_SIGNAL | ||
1166 | */ | ||
1167 | if (dsp->rx_init) { | ||
1168 | dsp->rx_init = 0; | ||
1169 | if (dsp->features.unordered) { | ||
1170 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
1171 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
1172 | & CMX_BUFF_MASK; | ||
1173 | } else { | ||
1174 | dsp->rx_R = 0; | ||
1175 | dsp->rx_W = dsp->cmx_delay; | ||
1176 | } | ||
1177 | } | ||
1178 | /* if frame contains time code, write directly */ | ||
1179 | if (dsp->features.unordered) { | ||
1180 | dsp->rx_W = (hh->id & CMX_BUFF_MASK); | ||
1181 | /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */ | ||
1182 | } | ||
1183 | /* | ||
1184 | * if we underrun (or maybe overrun), | ||
1185 | * we set our new read pointer, and write silence to buffer | ||
1186 | */ | ||
1187 | if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { | ||
1188 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1189 | printk(KERN_DEBUG | ||
1190 | "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " | ||
1191 | "maximum delay), adjusting read pointer! " | ||
1192 | "(inst %s)\n", (u_long)dsp, dsp->name); | ||
1193 | /* flush buffer */ | ||
1194 | if (dsp->features.unordered) { | ||
1195 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
1196 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
1197 | & CMX_BUFF_MASK; | ||
1198 | } else { | ||
1199 | dsp->rx_R = 0; | ||
1200 | dsp->rx_W = dsp->cmx_delay; | ||
1201 | } | ||
1202 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
1203 | } | ||
1204 | /* if we have reached double delay, jump back to middle */ | ||
1205 | if (dsp->cmx_delay) | ||
1206 | if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= | ||
1207 | (dsp->cmx_delay << 1)) { | ||
1208 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1209 | printk(KERN_DEBUG | ||
1210 | "cmx_receive(dsp=%lx): OVERRUN (because " | ||
1211 | "twice the delay is reached), adjusting " | ||
1212 | "read pointer! (inst %s)\n", | ||
1213 | (u_long)dsp, dsp->name); | ||
1214 | /* flush buffer */ | ||
1215 | if (dsp->features.unordered) { | ||
1216 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
1217 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
1218 | & CMX_BUFF_MASK; | ||
1219 | } else { | ||
1220 | dsp->rx_R = 0; | ||
1221 | dsp->rx_W = dsp->cmx_delay; | ||
1222 | } | ||
1223 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
1224 | } | ||
1225 | |||
1226 | /* show where to write */ | ||
1227 | #ifdef CMX_DEBUG | ||
1228 | printk(KERN_DEBUG | ||
1229 | "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", | ||
1230 | (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); | ||
1231 | #endif | ||
1232 | |||
1233 | /* write data into rx_buffer */ | ||
1234 | p = skb->data; | ||
1235 | d = dsp->rx_buff; | ||
1236 | w = dsp->rx_W; | ||
1237 | i = 0; | ||
1238 | ii = len; | ||
1239 | while (i < ii) { | ||
1240 | d[w++ & CMX_BUFF_MASK] = *p++; | ||
1241 | i++; | ||
1242 | } | ||
1243 | |||
1244 | /* increase write-pointer */ | ||
1245 | dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK); | ||
1246 | } | ||
1247 | |||
1248 | |||
1249 | /* | ||
1250 | * send (mixed) audio data to card and control jitter | ||
1251 | */ | ||
1252 | static void | ||
1253 | dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | ||
1254 | { | ||
1255 | struct dsp_conf *conf = dsp->conf; | ||
1256 | struct dsp *member, *other; | ||
1257 | register s32 sample; | ||
1258 | u8 *d, *p, *q, *o_q; | ||
1259 | struct sk_buff *nskb, *txskb; | ||
1260 | int r, rr, t, tt, o_r, o_rr; | ||
1261 | int preload = 0; | ||
1262 | struct mISDNhead *hh, *thh; | ||
1263 | |||
1264 | /* don't process if: */ | ||
1265 | if (!dsp->b_active) { /* if not active */ | ||
1266 | dsp->last_tx = 0; | ||
1267 | return; | ||
1268 | } | ||
1269 | if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ | ||
1270 | dsp->tx_R == dsp->tx_W && /* AND no tx-data */ | ||
1271 | !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ | ||
1272 | dsp->last_tx = 0; | ||
1273 | return; | ||
1274 | } | ||
1275 | |||
1276 | #ifdef CMX_DEBUG | ||
1277 | printk(KERN_DEBUG | ||
1278 | "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", | ||
1279 | members, dsp->name, conf, dsp->rx_R, dsp->rx_W); | ||
1280 | #endif | ||
1281 | |||
1282 | /* preload if we have delay set */ | ||
1283 | if (dsp->cmx_delay && !dsp->last_tx) { | ||
1284 | preload = len; | ||
1285 | if (preload < 128) | ||
1286 | preload = 128; | ||
1287 | } | ||
1288 | |||
1289 | /* PREPARE RESULT */ | ||
1290 | nskb = mI_alloc_skb(len + preload, GFP_ATOMIC); | ||
1291 | if (!nskb) { | ||
1292 | printk(KERN_ERR | ||
1293 | "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", | ||
1294 | len + preload); | ||
1295 | return; | ||
1296 | } | ||
1297 | hh = mISDN_HEAD_P(nskb); | ||
1298 | hh->prim = PH_DATA_REQ; | ||
1299 | hh->id = 0; | ||
1300 | dsp->last_tx = 1; | ||
1301 | |||
1302 | /* set pointers, indexes and stuff */ | ||
1303 | member = dsp; | ||
1304 | p = dsp->tx_buff; /* transmit data */ | ||
1305 | q = dsp->rx_buff; /* received data */ | ||
1306 | d = skb_put(nskb, preload + len); /* result */ | ||
1307 | t = dsp->tx_R; /* tx-pointers */ | ||
1308 | tt = dsp->tx_W; | ||
1309 | r = dsp->rx_R; /* rx-pointers */ | ||
1310 | rr = (r + len) & CMX_BUFF_MASK; | ||
1311 | |||
1312 | /* preload with silence, if required */ | ||
1313 | if (preload) { | ||
1314 | memset(d, dsp_silence, preload); | ||
1315 | d += preload; | ||
1316 | } | ||
1317 | |||
1318 | /* PROCESS TONES/TX-DATA ONLY */ | ||
1319 | if (dsp->tone.tone && dsp->tone.software) { | ||
1320 | /* -> copy tone */ | ||
1321 | dsp_tone_copy(dsp, d, len); | ||
1322 | dsp->tx_R = 0; /* clear tx buffer */ | ||
1323 | dsp->tx_W = 0; | ||
1324 | goto send_packet; | ||
1325 | } | ||
1326 | /* if we have tx-data but do not use mixing */ | ||
1327 | if (!dsp->tx_mix && t != tt) { | ||
1328 | /* -> send tx-data and continue when not enough */ | ||
1329 | #ifdef CMX_TX_DEBUG | ||
1330 | sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); | ||
1331 | #endif | ||
1332 | while (r != rr && t != tt) { | ||
1333 | #ifdef CMX_TX_DEBUG | ||
1334 | if (strlen(debugbuf) < 48) | ||
1335 | sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]); | ||
1336 | #endif | ||
1337 | *d++ = p[t]; /* write tx_buff */ | ||
1338 | t = (t+1) & CMX_BUFF_MASK; | ||
1339 | r = (r+1) & CMX_BUFF_MASK; | ||
1340 | } | ||
1341 | if (r == rr) { | ||
1342 | dsp->tx_R = t; | ||
1343 | #ifdef CMX_TX_DEBUG | ||
1344 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
1345 | #endif | ||
1346 | goto send_packet; | ||
1347 | } | ||
1348 | } | ||
1349 | #ifdef CMX_TX_DEBUG | ||
1350 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
1351 | #endif | ||
1352 | |||
1353 | /* PROCESS DATA (one member / no conf) */ | ||
1354 | if (!conf || members <= 1) { | ||
1355 | /* -> if echo is NOT enabled */ | ||
1356 | if (!dsp->echo) { | ||
1357 | /* -> send tx-data if available or use 0-volume */ | ||
1358 | while (r != rr && t != tt) { | ||
1359 | *d++ = p[t]; /* write tx_buff */ | ||
1360 | t = (t+1) & CMX_BUFF_MASK; | ||
1361 | r = (r+1) & CMX_BUFF_MASK; | ||
1362 | } | ||
1363 | if (r != rr) | ||
1364 | memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); | ||
1365 | /* -> if echo is enabled */ | ||
1366 | } else { | ||
1367 | /* | ||
1368 | * -> mix tx-data with echo if available, | ||
1369 | * or use echo only | ||
1370 | */ | ||
1371 | while (r != rr && t != tt) { | ||
1372 | *d++ = dsp_audio_mix_law[(p[t]<<8)|q[r]]; | ||
1373 | t = (t+1) & CMX_BUFF_MASK; | ||
1374 | r = (r+1) & CMX_BUFF_MASK; | ||
1375 | } | ||
1376 | while (r != rr) { | ||
1377 | *d++ = q[r]; /* echo */ | ||
1378 | r = (r+1) & CMX_BUFF_MASK; | ||
1379 | } | ||
1380 | } | ||
1381 | dsp->tx_R = t; | ||
1382 | goto send_packet; | ||
1383 | } | ||
1384 | /* PROCESS DATA (two members) */ | ||
1385 | #ifdef CMX_CONF_DEBUG | ||
1386 | if (0) { | ||
1387 | #else | ||
1388 | if (members == 2) { | ||
1389 | #endif | ||
1390 | /* "other" becomes other party */ | ||
1391 | other = (list_entry(conf->mlist.next, | ||
1392 | struct dsp_conf_member, list))->dsp; | ||
1393 | if (other == member) | ||
1394 | other = (list_entry(conf->mlist.prev, | ||
1395 | struct dsp_conf_member, list))->dsp; | ||
1396 | o_q = other->rx_buff; /* received data */ | ||
1397 | o_rr = (other->rx_R + len) & CMX_BUFF_MASK; | ||
1398 | /* end of rx-pointer */ | ||
1399 | o_r = (o_rr - rr + r) & CMX_BUFF_MASK; | ||
1400 | /* start rx-pointer at current read position*/ | ||
1401 | /* -> if echo is NOT enabled */ | ||
1402 | if (!dsp->echo) { | ||
1403 | /* | ||
1404 | * -> copy other member's rx-data, | ||
1405 | * if tx-data is available, mix | ||
1406 | */ | ||
1407 | while (o_r != o_rr && t != tt) { | ||
1408 | *d++ = dsp_audio_mix_law[(p[t]<<8)|o_q[o_r]]; | ||
1409 | t = (t+1) & CMX_BUFF_MASK; | ||
1410 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1411 | } | ||
1412 | while (o_r != o_rr) { | ||
1413 | *d++ = o_q[o_r]; | ||
1414 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1415 | } | ||
1416 | /* -> if echo is enabled */ | ||
1417 | } else { | ||
1418 | /* | ||
1419 | * -> mix other member's rx-data with echo, | ||
1420 | * if tx-data is available, mix | ||
1421 | */ | ||
1422 | while (r != rr && t != tt) { | ||
1423 | sample = dsp_audio_law_to_s32[p[t]] + | ||
1424 | dsp_audio_law_to_s32[q[r]] + | ||
1425 | dsp_audio_law_to_s32[o_q[o_r]]; | ||
1426 | if (sample < -32768) | ||
1427 | sample = -32768; | ||
1428 | else if (sample > 32767) | ||
1429 | sample = 32767; | ||
1430 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1431 | /* tx-data + rx_data + echo */ | ||
1432 | t = (t+1) & CMX_BUFF_MASK; | ||
1433 | r = (r+1) & CMX_BUFF_MASK; | ||
1434 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1435 | } | ||
1436 | while (r != rr) { | ||
1437 | *d++ = dsp_audio_mix_law[(q[r]<<8)|o_q[o_r]]; | ||
1438 | r = (r+1) & CMX_BUFF_MASK; | ||
1439 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
1440 | } | ||
1441 | } | ||
1442 | dsp->tx_R = t; | ||
1443 | goto send_packet; | ||
1444 | } | ||
1445 | #ifdef DSP_NEVER_DEFINED | ||
1446 | } | ||
1447 | #endif | ||
1448 | /* PROCESS DATA (three or more members) */ | ||
1449 | /* -> if echo is NOT enabled */ | ||
1450 | if (!dsp->echo) { | ||
1451 | /* | ||
1452 | * -> substract rx-data from conf-data, | ||
1453 | * if tx-data is available, mix | ||
1454 | */ | ||
1455 | while (r != rr && t != tt) { | ||
1456 | sample = dsp_audio_law_to_s32[p[t]] + *c++ - | ||
1457 | dsp_audio_law_to_s32[q[r]]; | ||
1458 | if (sample < -32768) | ||
1459 | sample = -32768; | ||
1460 | else if (sample > 32767) | ||
1461 | sample = 32767; | ||
1462 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1463 | /* conf-rx+tx */ | ||
1464 | r = (r+1) & CMX_BUFF_MASK; | ||
1465 | t = (t+1) & CMX_BUFF_MASK; | ||
1466 | } | ||
1467 | while (r != rr) { | ||
1468 | sample = *c++ - dsp_audio_law_to_s32[q[r]]; | ||
1469 | if (sample < -32768) | ||
1470 | sample = -32768; | ||
1471 | else if (sample > 32767) | ||
1472 | sample = 32767; | ||
1473 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1474 | /* conf-rx */ | ||
1475 | r = (r+1) & CMX_BUFF_MASK; | ||
1476 | } | ||
1477 | /* -> if echo is enabled */ | ||
1478 | } else { | ||
1479 | /* | ||
1480 | * -> encode conf-data, if tx-data | ||
1481 | * is available, mix | ||
1482 | */ | ||
1483 | while (r != rr && t != tt) { | ||
1484 | sample = dsp_audio_law_to_s32[p[t]] + *c++; | ||
1485 | if (sample < -32768) | ||
1486 | sample = -32768; | ||
1487 | else if (sample > 32767) | ||
1488 | sample = 32767; | ||
1489 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1490 | /* conf(echo)+tx */ | ||
1491 | t = (t+1) & CMX_BUFF_MASK; | ||
1492 | r = (r+1) & CMX_BUFF_MASK; | ||
1493 | } | ||
1494 | while (r != rr) { | ||
1495 | sample = *c++; | ||
1496 | if (sample < -32768) | ||
1497 | sample = -32768; | ||
1498 | else if (sample > 32767) | ||
1499 | sample = 32767; | ||
1500 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
1501 | /* conf(echo) */ | ||
1502 | r = (r+1) & CMX_BUFF_MASK; | ||
1503 | } | ||
1504 | } | ||
1505 | dsp->tx_R = t; | ||
1506 | goto send_packet; | ||
1507 | |||
1508 | send_packet: | ||
1509 | /* | ||
1510 | * send tx-data if enabled - don't filter, | ||
1511 | * becuase we want what we send, not what we filtered | ||
1512 | */ | ||
1513 | if (dsp->tx_data) { | ||
1514 | /* PREPARE RESULT */ | ||
1515 | txskb = mI_alloc_skb(len, GFP_ATOMIC); | ||
1516 | if (!txskb) { | ||
1517 | printk(KERN_ERR | ||
1518 | "FATAL ERROR in mISDN_dsp.o: " | ||
1519 | "cannot alloc %d bytes\n", len); | ||
1520 | } else { | ||
1521 | thh = mISDN_HEAD_P(txskb); | ||
1522 | thh->prim = DL_DATA_REQ; | ||
1523 | thh->id = 0; | ||
1524 | memcpy(skb_put(txskb, len), nskb->data+preload, len); | ||
1525 | /* queue (trigger later) */ | ||
1526 | skb_queue_tail(&dsp->sendq, txskb); | ||
1527 | } | ||
1528 | } | ||
1529 | /* adjust volume */ | ||
1530 | if (dsp->tx_volume) | ||
1531 | dsp_change_volume(nskb, dsp->tx_volume); | ||
1532 | /* pipeline */ | ||
1533 | if (dsp->pipeline.inuse) | ||
1534 | dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); | ||
1535 | /* crypt */ | ||
1536 | if (dsp->bf_enable) | ||
1537 | dsp_bf_encrypt(dsp, nskb->data, nskb->len); | ||
1538 | /* queue and trigger */ | ||
1539 | skb_queue_tail(&dsp->sendq, nskb); | ||
1540 | schedule_work(&dsp->workq); | ||
1541 | } | ||
1542 | |||
1543 | u32 samplecount; | ||
1544 | struct timer_list dsp_spl_tl; | ||
1545 | u32 dsp_spl_jiffies; /* calculate the next time to fire */ | ||
1546 | u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ | ||
1547 | struct timeval dsp_start_tv; /* time at start of calculation */ | ||
1548 | |||
1549 | void | ||
1550 | dsp_cmx_send(void *arg) | ||
1551 | { | ||
1552 | struct dsp_conf *conf; | ||
1553 | struct dsp_conf_member *member; | ||
1554 | struct dsp *dsp; | ||
1555 | int mustmix, members; | ||
1556 | s32 mixbuffer[MAX_POLL+100], *c; | ||
1557 | u8 *p, *q; | ||
1558 | int r, rr; | ||
1559 | int jittercheck = 0, delay, i; | ||
1560 | u_long flags; | ||
1561 | struct timeval tv; | ||
1562 | u32 elapsed; | ||
1563 | s16 length; | ||
1564 | |||
1565 | /* lock */ | ||
1566 | spin_lock_irqsave(&dsp_lock, flags); | ||
1567 | |||
1568 | if (!dsp_start_tv.tv_sec) { | ||
1569 | do_gettimeofday(&dsp_start_tv); | ||
1570 | length = dsp_poll; | ||
1571 | } else { | ||
1572 | do_gettimeofday(&tv); | ||
1573 | elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000) | ||
1574 | + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125)); | ||
1575 | dsp_start_tv.tv_sec = tv.tv_sec; | ||
1576 | dsp_start_tv.tv_usec = tv.tv_usec; | ||
1577 | length = elapsed; | ||
1578 | } | ||
1579 | if (length > MAX_POLL + 100) | ||
1580 | length = MAX_POLL + 100; | ||
1581 | /* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n", | ||
1582 | length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16, | ||
1583 | dsp_poll_diff & 0xffff); | ||
1584 | */ | ||
1585 | |||
1586 | /* | ||
1587 | * check if jitter needs to be checked | ||
1588 | * (this is about every second = 8192 samples) | ||
1589 | */ | ||
1590 | samplecount += length; | ||
1591 | if ((samplecount & 8191) < length) | ||
1592 | jittercheck = 1; | ||
1593 | |||
1594 | /* loop all members that do not require conference mixing */ | ||
1595 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
1596 | if (dsp->hdlc) | ||
1597 | continue; | ||
1598 | conf = dsp->conf; | ||
1599 | mustmix = 0; | ||
1600 | members = 0; | ||
1601 | if (conf) { | ||
1602 | members = count_list_member(&conf->mlist); | ||
1603 | #ifdef CMX_CONF_DEBUG | ||
1604 | if (conf->software && members > 1) | ||
1605 | #else | ||
1606 | if (conf->software && members > 2) | ||
1607 | #endif | ||
1608 | mustmix = 1; | ||
1609 | } | ||
1610 | |||
1611 | /* transmission required */ | ||
1612 | if (!mustmix) { | ||
1613 | dsp_cmx_send_member(dsp, length, mixbuffer, members); | ||
1614 | |||
1615 | /* | ||
1616 | * unused mixbuffer is given to prevent a | ||
1617 | * potential null-pointer-bug | ||
1618 | */ | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | /* loop all members that require conference mixing */ | ||
1623 | list_for_each_entry(conf, &conf_ilist, list) { | ||
1624 | /* count members and check hardware */ | ||
1625 | members = count_list_member(&conf->mlist); | ||
1626 | #ifdef CMX_CONF_DEBUG | ||
1627 | if (conf->software && members > 1) { | ||
1628 | #else | ||
1629 | if (conf->software && members > 2) { | ||
1630 | #endif | ||
1631 | /* check for hdlc conf */ | ||
1632 | member = list_entry(conf->mlist.next, | ||
1633 | struct dsp_conf_member, list); | ||
1634 | if (member->dsp->hdlc) | ||
1635 | continue; | ||
1636 | /* mix all data */ | ||
1637 | memset(mixbuffer, 0, length*sizeof(s32)); | ||
1638 | list_for_each_entry(member, &conf->mlist, list) { | ||
1639 | dsp = member->dsp; | ||
1640 | /* get range of data to mix */ | ||
1641 | c = mixbuffer; | ||
1642 | q = dsp->rx_buff; | ||
1643 | r = dsp->rx_R; | ||
1644 | rr = (r + length) & CMX_BUFF_MASK; | ||
1645 | /* add member's data */ | ||
1646 | while (r != rr) { | ||
1647 | *c++ += dsp_audio_law_to_s32[q[r]]; | ||
1648 | r = (r+1) & CMX_BUFF_MASK; | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | /* process each member */ | ||
1653 | list_for_each_entry(member, &conf->mlist, list) { | ||
1654 | /* transmission */ | ||
1655 | dsp_cmx_send_member(member->dsp, length, | ||
1656 | mixbuffer, members); | ||
1657 | } | ||
1658 | } | ||
1659 | } | ||
1660 | |||
1661 | /* delete rx-data, increment buffers, change pointers */ | ||
1662 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
1663 | if (dsp->hdlc) | ||
1664 | continue; | ||
1665 | p = dsp->rx_buff; | ||
1666 | q = dsp->tx_buff; | ||
1667 | r = dsp->rx_R; | ||
1668 | /* move receive pointer when receiving */ | ||
1669 | if (!dsp->rx_is_off) { | ||
1670 | rr = (r + length) & CMX_BUFF_MASK; | ||
1671 | /* delete rx-data */ | ||
1672 | while (r != rr) { | ||
1673 | p[r] = dsp_silence; | ||
1674 | r = (r+1) & CMX_BUFF_MASK; | ||
1675 | } | ||
1676 | /* increment rx-buffer pointer */ | ||
1677 | dsp->rx_R = r; /* write incremented read pointer */ | ||
1678 | } | ||
1679 | |||
1680 | /* check current rx_delay */ | ||
1681 | delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; | ||
1682 | if (delay >= CMX_BUFF_HALF) | ||
1683 | delay = 0; /* will be the delay before next write */ | ||
1684 | /* check for lower delay */ | ||
1685 | if (delay < dsp->rx_delay[0]) | ||
1686 | dsp->rx_delay[0] = delay; | ||
1687 | /* check current tx_delay */ | ||
1688 | delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; | ||
1689 | if (delay >= CMX_BUFF_HALF) | ||
1690 | delay = 0; /* will be the delay before next write */ | ||
1691 | /* check for lower delay */ | ||
1692 | if (delay < dsp->tx_delay[0]) | ||
1693 | dsp->tx_delay[0] = delay; | ||
1694 | if (jittercheck) { | ||
1695 | /* find the lowest of all rx_delays */ | ||
1696 | delay = dsp->rx_delay[0]; | ||
1697 | i = 1; | ||
1698 | while (i < MAX_SECONDS_JITTER_CHECK) { | ||
1699 | if (delay > dsp->rx_delay[i]) | ||
1700 | delay = dsp->rx_delay[i]; | ||
1701 | i++; | ||
1702 | } | ||
1703 | /* | ||
1704 | * remove rx_delay only if we have delay AND we | ||
1705 | * have not preset cmx_delay | ||
1706 | */ | ||
1707 | if (delay && !dsp->cmx_delay) { | ||
1708 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1709 | printk(KERN_DEBUG | ||
1710 | "%s lowest rx_delay of %d bytes for" | ||
1711 | " dsp %s are now removed.\n", | ||
1712 | __func__, delay, | ||
1713 | dsp->name); | ||
1714 | r = dsp->rx_R; | ||
1715 | rr = (r + delay) & CMX_BUFF_MASK; | ||
1716 | /* delete rx-data */ | ||
1717 | while (r != rr) { | ||
1718 | p[r] = dsp_silence; | ||
1719 | r = (r+1) & CMX_BUFF_MASK; | ||
1720 | } | ||
1721 | /* increment rx-buffer pointer */ | ||
1722 | dsp->rx_R = r; | ||
1723 | /* write incremented read pointer */ | ||
1724 | } | ||
1725 | /* find the lowest of all tx_delays */ | ||
1726 | delay = dsp->tx_delay[0]; | ||
1727 | i = 1; | ||
1728 | while (i < MAX_SECONDS_JITTER_CHECK) { | ||
1729 | if (delay > dsp->tx_delay[i]) | ||
1730 | delay = dsp->tx_delay[i]; | ||
1731 | i++; | ||
1732 | } | ||
1733 | /* | ||
1734 | * remove delay only if we have delay AND we | ||
1735 | * have enabled tx_dejitter | ||
1736 | */ | ||
1737 | if (delay && dsp->tx_dejitter) { | ||
1738 | if (dsp_debug & DEBUG_DSP_CMX) | ||
1739 | printk(KERN_DEBUG | ||
1740 | "%s lowest tx_delay of %d bytes for" | ||
1741 | " dsp %s are now removed.\n", | ||
1742 | __func__, delay, | ||
1743 | dsp->name); | ||
1744 | r = dsp->tx_R; | ||
1745 | rr = (r + delay) & CMX_BUFF_MASK; | ||
1746 | /* delete tx-data */ | ||
1747 | while (r != rr) { | ||
1748 | q[r] = dsp_silence; | ||
1749 | r = (r+1) & CMX_BUFF_MASK; | ||
1750 | } | ||
1751 | /* increment rx-buffer pointer */ | ||
1752 | dsp->tx_R = r; | ||
1753 | /* write incremented read pointer */ | ||
1754 | } | ||
1755 | /* scroll up delays */ | ||
1756 | i = MAX_SECONDS_JITTER_CHECK - 1; | ||
1757 | while (i) { | ||
1758 | dsp->rx_delay[i] = dsp->rx_delay[i-1]; | ||
1759 | dsp->tx_delay[i] = dsp->tx_delay[i-1]; | ||
1760 | i--; | ||
1761 | } | ||
1762 | dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ | ||
1763 | dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ | ||
1764 | } | ||
1765 | } | ||
1766 | |||
1767 | /* if next event would be in the past ... */ | ||
1768 | if ((s32)(dsp_spl_jiffies+dsp_tics-jiffies) <= 0) | ||
1769 | dsp_spl_jiffies = jiffies + 1; | ||
1770 | else | ||
1771 | dsp_spl_jiffies += dsp_tics; | ||
1772 | |||
1773 | dsp_spl_tl.expires = dsp_spl_jiffies; | ||
1774 | add_timer(&dsp_spl_tl); | ||
1775 | |||
1776 | /* unlock */ | ||
1777 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
1778 | } | ||
1779 | |||
1780 | /* | ||
1781 | * audio data is transmitted from upper layer to the dsp | ||
1782 | */ | ||
1783 | void | ||
1784 | dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) | ||
1785 | { | ||
1786 | u_int w, ww; | ||
1787 | u8 *d, *p; | ||
1788 | int space; /* todo: , l = skb->len; */ | ||
1789 | #ifdef CMX_TX_DEBUG | ||
1790 | char debugbuf[256] = ""; | ||
1791 | #endif | ||
1792 | |||
1793 | /* check if there is enough space, and then copy */ | ||
1794 | w = dsp->tx_W; | ||
1795 | ww = dsp->tx_R; | ||
1796 | p = dsp->tx_buff; | ||
1797 | d = skb->data; | ||
1798 | space = ww-w; | ||
1799 | if (space <= 0) | ||
1800 | space += CMX_BUFF_SIZE; | ||
1801 | /* write-pointer should not overrun nor reach read pointer */ | ||
1802 | if (space-1 < skb->len) | ||
1803 | /* write to the space we have left */ | ||
1804 | ww = (ww - 1) & CMX_BUFF_MASK; | ||
1805 | else | ||
1806 | /* write until all byte are copied */ | ||
1807 | ww = (w + skb->len) & CMX_BUFF_MASK; | ||
1808 | dsp->tx_W = ww; | ||
1809 | |||
1810 | /* show current buffer */ | ||
1811 | #ifdef CMX_DEBUG | ||
1812 | printk(KERN_DEBUG | ||
1813 | "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", | ||
1814 | (u_long)dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->name); | ||
1815 | #endif | ||
1816 | |||
1817 | /* copy transmit data to tx-buffer */ | ||
1818 | #ifdef CMX_TX_DEBUG | ||
1819 | sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); | ||
1820 | #endif | ||
1821 | while (w != ww) { | ||
1822 | #ifdef CMX_TX_DEBUG | ||
1823 | if (strlen(debugbuf) < 48) | ||
1824 | sprintf(debugbuf+strlen(debugbuf), " %02x", *d); | ||
1825 | #endif | ||
1826 | p[w] = *d++; | ||
1827 | w = (w+1) & CMX_BUFF_MASK; | ||
1828 | } | ||
1829 | #ifdef CMX_TX_DEBUG | ||
1830 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
1831 | #endif | ||
1832 | |||
1833 | } | ||
1834 | |||
1835 | /* | ||
1836 | * hdlc data is received from card and sent to all members. | ||
1837 | */ | ||
1838 | void | ||
1839 | dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) | ||
1840 | { | ||
1841 | struct sk_buff *nskb = NULL; | ||
1842 | struct dsp_conf_member *member; | ||
1843 | struct mISDNhead *hh; | ||
1844 | |||
1845 | /* not if not active */ | ||
1846 | if (!dsp->b_active) | ||
1847 | return; | ||
1848 | |||
1849 | /* check if we have sompen */ | ||
1850 | if (skb->len < 1) | ||
1851 | return; | ||
1852 | |||
1853 | /* no conf */ | ||
1854 | if (!dsp->conf) { | ||
1855 | /* in case of hardware (echo) */ | ||
1856 | if (dsp->pcm_slot_tx >= 0) | ||
1857 | return; | ||
1858 | if (dsp->echo) | ||
1859 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1860 | if (nskb) { | ||
1861 | hh = mISDN_HEAD_P(nskb); | ||
1862 | hh->prim = PH_DATA_REQ; | ||
1863 | hh->id = 0; | ||
1864 | skb_queue_tail(&dsp->sendq, nskb); | ||
1865 | schedule_work(&dsp->workq); | ||
1866 | } | ||
1867 | return; | ||
1868 | } | ||
1869 | /* in case of hardware conference */ | ||
1870 | if (dsp->conf->hardware) | ||
1871 | return; | ||
1872 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
1873 | if (dsp->echo || member->dsp != dsp) { | ||
1874 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1875 | if (nskb) { | ||
1876 | hh = mISDN_HEAD_P(nskb); | ||
1877 | hh->prim = PH_DATA_REQ; | ||
1878 | hh->id = 0; | ||
1879 | skb_queue_tail(&member->dsp->sendq, nskb); | ||
1880 | schedule_work(&member->dsp->workq); | ||
1881 | } | ||
1882 | } | ||
1883 | } | ||
1884 | } | ||
1885 | |||
1886 | |||
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c new file mode 100644 index 000000000000..2f10ed82c0db --- /dev/null +++ b/drivers/isdn/mISDN/dsp_core.c | |||
@@ -0,0 +1,1191 @@ | |||
1 | /* | ||
2 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
3 | * Based on source code structure by | ||
4 | * Karsten Keil (keil@isdn4linux.de) | ||
5 | * | ||
6 | * This file is (c) under GNU PUBLIC LICENSE | ||
7 | * For changes and modifications please read | ||
8 | * ../../../Documentation/isdn/mISDN.cert | ||
9 | * | ||
10 | * Thanks to Karsten Keil (great drivers) | ||
11 | * Cologne Chip (great chips) | ||
12 | * | ||
13 | * This module does: | ||
14 | * Real-time tone generation | ||
15 | * DTMF detection | ||
16 | * Real-time cross-connection and conferrence | ||
17 | * Compensate jitter due to system load and hardware fault. | ||
18 | * All features are done in kernel space and will be realized | ||
19 | * using hardware, if available and supported by chip set. | ||
20 | * Blowfish encryption/decryption | ||
21 | */ | ||
22 | |||
23 | /* STRUCTURE: | ||
24 | * | ||
25 | * The dsp module provides layer 2 for b-channels (64kbit). It provides | ||
26 | * transparent audio forwarding with special digital signal processing: | ||
27 | * | ||
28 | * - (1) generation of tones | ||
29 | * - (2) detection of dtmf tones | ||
30 | * - (3) crossconnecting and conferences (clocking) | ||
31 | * - (4) echo generation for delay test | ||
32 | * - (5) volume control | ||
33 | * - (6) disable receive data | ||
34 | * - (7) pipeline | ||
35 | * - (8) encryption/decryption | ||
36 | * | ||
37 | * Look: | ||
38 | * TX RX | ||
39 | * ------upper layer------ | ||
40 | * | ^ | ||
41 | * | |(6) | ||
42 | * v | | ||
43 | * +-----+-------------+-----+ | ||
44 | * |(3)(4) | | ||
45 | * | CMX | | ||
46 | * | | | ||
47 | * | +-------------+ | ||
48 | * | | ^ | ||
49 | * | | | | ||
50 | * |+---------+| +----+----+ | ||
51 | * ||(1) || |(2) | | ||
52 | * || || | | | ||
53 | * || Tones || | DTMF | | ||
54 | * || || | | | ||
55 | * || || | | | ||
56 | * |+----+----+| +----+----+ | ||
57 | * +-----+-----+ ^ | ||
58 | * | | | ||
59 | * v | | ||
60 | * +----+----+ +----+----+ | ||
61 | * |(5) | |(5) | | ||
62 | * | | | | | ||
63 | * |TX Volume| |RX Volume| | ||
64 | * | | | | | ||
65 | * | | | | | ||
66 | * +----+----+ +----+----+ | ||
67 | * | ^ | ||
68 | * | | | ||
69 | * v | | ||
70 | * +----+-------------+----+ | ||
71 | * |(7) | | ||
72 | * | | | ||
73 | * | Pipeline Processing | | ||
74 | * | | | ||
75 | * | | | ||
76 | * +----+-------------+----+ | ||
77 | * | ^ | ||
78 | * | | | ||
79 | * v | | ||
80 | * +----+----+ +----+----+ | ||
81 | * |(8) | |(8) | | ||
82 | * | | | | | ||
83 | * | Encrypt | | Decrypt | | ||
84 | * | | | | | ||
85 | * | | | | | ||
86 | * +----+----+ +----+----+ | ||
87 | * | ^ | ||
88 | * | | | ||
89 | * v | | ||
90 | * ------card layer------ | ||
91 | * TX RX | ||
92 | * | ||
93 | * Above you can see the logical data flow. If software is used to do the | ||
94 | * process, it is actually the real data flow. If hardware is used, data | ||
95 | * may not flow, but hardware commands to the card, to provide the data flow | ||
96 | * as shown. | ||
97 | * | ||
98 | * NOTE: The channel must be activated in order to make dsp work, even if | ||
99 | * no data flow to the upper layer is intended. Activation can be done | ||
100 | * after and before controlling the setting using PH_CONTROL requests. | ||
101 | * | ||
102 | * DTMF: Will be detected by hardware if possible. It is done before CMX | ||
103 | * processing. | ||
104 | * | ||
105 | * Tones: Will be generated via software if endless looped audio fifos are | ||
106 | * not supported by hardware. Tones will override all data from CMX. | ||
107 | * It is not required to join a conference to use tones at any time. | ||
108 | * | ||
109 | * CMX: Is transparent when not used. When it is used, it will do | ||
110 | * crossconnections and conferences via software if not possible through | ||
111 | * hardware. If hardware capability is available, hardware is used. | ||
112 | * | ||
113 | * Echo: Is generated by CMX and is used to check performane of hard and | ||
114 | * software CMX. | ||
115 | * | ||
116 | * The CMX has special functions for conferences with one, two and more | ||
117 | * members. It will allow different types of data flow. Receive and transmit | ||
118 | * data to/form upper layer may be swithed on/off individually without loosing | ||
119 | * features of CMX, Tones and DTMF. | ||
120 | * | ||
121 | * Echo Cancellation: Sometimes we like to cancel echo from the interface. | ||
122 | * Note that a VoIP call may not have echo caused by the IP phone. The echo | ||
123 | * is generated by the telephone line connected to it. Because the delay | ||
124 | * is high, it becomes an echo. RESULT: Echo Cachelation is required if | ||
125 | * both echo AND delay is applied to an interface. | ||
126 | * Remember that software CMX always generates a more or less delay. | ||
127 | * | ||
128 | * If all used features can be realized in hardware, and if transmit and/or | ||
129 | * receive data ist disabled, the card may not send/receive any data at all. | ||
130 | * Not receiving is usefull if only announcements are played. Not sending is | ||
131 | * usefull if an answering machine records audio. Not sending and receiving is | ||
132 | * usefull during most states of the call. If supported by hardware, tones | ||
133 | * will be played without cpu load. Small PBXs and NT-Mode applications will | ||
134 | * not need expensive hardware when processing calls. | ||
135 | * | ||
136 | * | ||
137 | * LOCKING: | ||
138 | * | ||
139 | * When data is received from upper or lower layer (card), the complete dsp | ||
140 | * module is locked by a global lock. This lock MUST lock irq, because it | ||
141 | * must lock timer events by DSP poll timer. | ||
142 | * When data is ready to be transmitted down, the data is queued and sent | ||
143 | * outside lock and timer event. | ||
144 | * PH_CONTROL must not change any settings, join or split conference members | ||
145 | * during process of data. | ||
146 | * | ||
147 | * HDLC: | ||
148 | * | ||
149 | * It works quite the same as transparent, except that HDLC data is forwarded | ||
150 | * to all other conference members if no hardware bridging is possible. | ||
151 | * Send data will be writte to sendq. Sendq will be sent if confirm is received. | ||
152 | * Conference cannot join, if one member is not hdlc. | ||
153 | * | ||
154 | */ | ||
155 | |||
156 | #include <linux/delay.h> | ||
157 | #include <linux/mISDNif.h> | ||
158 | #include <linux/mISDNdsp.h> | ||
159 | #include <linux/module.h> | ||
160 | #include <linux/vmalloc.h> | ||
161 | #include "core.h" | ||
162 | #include "dsp.h" | ||
163 | |||
164 | const char *mISDN_dsp_revision = "2.0"; | ||
165 | |||
166 | static int debug; | ||
167 | static int options; | ||
168 | static int poll; | ||
169 | static int dtmfthreshold = 100; | ||
170 | |||
171 | MODULE_AUTHOR("Andreas Eversberg"); | ||
172 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
173 | module_param(options, uint, S_IRUGO | S_IWUSR); | ||
174 | module_param(poll, uint, S_IRUGO | S_IWUSR); | ||
175 | module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR); | ||
176 | MODULE_LICENSE("GPL"); | ||
177 | |||
178 | /*int spinnest = 0;*/ | ||
179 | |||
180 | spinlock_t dsp_lock; /* global dsp lock */ | ||
181 | struct list_head dsp_ilist; | ||
182 | struct list_head conf_ilist; | ||
183 | int dsp_debug; | ||
184 | int dsp_options; | ||
185 | int dsp_poll, dsp_tics; | ||
186 | |||
187 | /* check if rx may be turned off or must be turned on */ | ||
188 | static void | ||
189 | dsp_rx_off_member(struct dsp *dsp) | ||
190 | { | ||
191 | struct mISDN_ctrl_req cq; | ||
192 | int rx_off = 1; | ||
193 | |||
194 | if (!dsp->features_rx_off) | ||
195 | return; | ||
196 | |||
197 | /* not disabled */ | ||
198 | if (!dsp->rx_disabled) | ||
199 | rx_off = 0; | ||
200 | /* software dtmf */ | ||
201 | else if (dsp->dtmf.software) | ||
202 | rx_off = 0; | ||
203 | /* echo in software */ | ||
204 | else if (dsp->echo && dsp->pcm_slot_tx < 0) | ||
205 | rx_off = 0; | ||
206 | /* bridge in software */ | ||
207 | else if (dsp->conf) { | ||
208 | if (dsp->conf->software) | ||
209 | rx_off = 0; | ||
210 | } | ||
211 | |||
212 | if (rx_off == dsp->rx_is_off) | ||
213 | return; | ||
214 | |||
215 | if (!dsp->ch.peer) { | ||
216 | if (dsp_debug & DEBUG_DSP_CORE) | ||
217 | printk(KERN_DEBUG "%s: no peer, no rx_off\n", | ||
218 | __func__); | ||
219 | return; | ||
220 | } | ||
221 | cq.op = MISDN_CTRL_RX_OFF; | ||
222 | cq.p1 = rx_off; | ||
223 | if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { | ||
224 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", | ||
225 | __func__); | ||
226 | return; | ||
227 | } | ||
228 | dsp->rx_is_off = rx_off; | ||
229 | if (dsp_debug & DEBUG_DSP_CORE) | ||
230 | printk(KERN_DEBUG "%s: %s set rx_off = %d\n", | ||
231 | __func__, dsp->name, rx_off); | ||
232 | } | ||
233 | static void | ||
234 | dsp_rx_off(struct dsp *dsp) | ||
235 | { | ||
236 | struct dsp_conf_member *member; | ||
237 | |||
238 | if (dsp_options & DSP_OPT_NOHARDWARE) | ||
239 | return; | ||
240 | |||
241 | /* no conf */ | ||
242 | if (!dsp->conf) { | ||
243 | dsp_rx_off_member(dsp); | ||
244 | return; | ||
245 | } | ||
246 | /* check all members in conf */ | ||
247 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
248 | dsp_rx_off_member(member->dsp); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | static int | ||
253 | dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) | ||
254 | { | ||
255 | struct sk_buff *nskb; | ||
256 | int ret = 0; | ||
257 | int cont; | ||
258 | u8 *data; | ||
259 | int len; | ||
260 | |||
261 | if (skb->len < sizeof(int)) | ||
262 | printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__); | ||
263 | cont = *((int *)skb->data); | ||
264 | len = skb->len - sizeof(int); | ||
265 | data = skb->data + sizeof(int); | ||
266 | |||
267 | switch (cont) { | ||
268 | case DTMF_TONE_START: /* turn on DTMF */ | ||
269 | if (dsp->hdlc) { | ||
270 | ret = -EINVAL; | ||
271 | break; | ||
272 | } | ||
273 | if (dsp_debug & DEBUG_DSP_CORE) | ||
274 | printk(KERN_DEBUG "%s: start dtmf\n", __func__); | ||
275 | if (len == sizeof(int)) { | ||
276 | printk(KERN_NOTICE "changing DTMF Threshold " | ||
277 | "to %d\n", *((int *)data)); | ||
278 | dsp->dtmf.treshold = (*(int *)data) * 10000; | ||
279 | } | ||
280 | /* init goertzel */ | ||
281 | dsp_dtmf_goertzel_init(dsp); | ||
282 | |||
283 | /* check dtmf hardware */ | ||
284 | dsp_dtmf_hardware(dsp); | ||
285 | break; | ||
286 | case DTMF_TONE_STOP: /* turn off DTMF */ | ||
287 | if (dsp_debug & DEBUG_DSP_CORE) | ||
288 | printk(KERN_DEBUG "%s: stop dtmf\n", __func__); | ||
289 | dsp->dtmf.hardware = 0; | ||
290 | dsp->dtmf.software = 0; | ||
291 | break; | ||
292 | case DSP_CONF_JOIN: /* join / update conference */ | ||
293 | if (len < sizeof(int)) { | ||
294 | ret = -EINVAL; | ||
295 | break; | ||
296 | } | ||
297 | if (*((u32 *)data) == 0) | ||
298 | goto conf_split; | ||
299 | if (dsp_debug & DEBUG_DSP_CORE) | ||
300 | printk(KERN_DEBUG "%s: join conference %d\n", | ||
301 | __func__, *((u32 *)data)); | ||
302 | ret = dsp_cmx_conf(dsp, *((u32 *)data)); | ||
303 | /* dsp_cmx_hardware will also be called here */ | ||
304 | dsp_rx_off(dsp); | ||
305 | if (dsp_debug & DEBUG_DSP_CMX) | ||
306 | dsp_cmx_debug(dsp); | ||
307 | break; | ||
308 | case DSP_CONF_SPLIT: /* remove from conference */ | ||
309 | conf_split: | ||
310 | if (dsp_debug & DEBUG_DSP_CORE) | ||
311 | printk(KERN_DEBUG "%s: release conference\n", __func__); | ||
312 | ret = dsp_cmx_conf(dsp, 0); | ||
313 | /* dsp_cmx_hardware will also be called here */ | ||
314 | if (dsp_debug & DEBUG_DSP_CMX) | ||
315 | dsp_cmx_debug(dsp); | ||
316 | dsp_rx_off(dsp); | ||
317 | break; | ||
318 | case DSP_TONE_PATT_ON: /* play tone */ | ||
319 | if (dsp->hdlc) { | ||
320 | ret = -EINVAL; | ||
321 | break; | ||
322 | } | ||
323 | if (len < sizeof(int)) { | ||
324 | ret = -EINVAL; | ||
325 | break; | ||
326 | } | ||
327 | if (dsp_debug & DEBUG_DSP_CORE) | ||
328 | printk(KERN_DEBUG "%s: turn tone 0x%x on\n", | ||
329 | __func__, *((int *)skb->data)); | ||
330 | ret = dsp_tone(dsp, *((int *)data)); | ||
331 | if (!ret) { | ||
332 | dsp_cmx_hardware(dsp->conf, dsp); | ||
333 | dsp_rx_off(dsp); | ||
334 | } | ||
335 | if (!dsp->tone.tone) | ||
336 | goto tone_off; | ||
337 | break; | ||
338 | case DSP_TONE_PATT_OFF: /* stop tone */ | ||
339 | if (dsp->hdlc) { | ||
340 | ret = -EINVAL; | ||
341 | break; | ||
342 | } | ||
343 | if (dsp_debug & DEBUG_DSP_CORE) | ||
344 | printk(KERN_DEBUG "%s: turn tone off\n", __func__); | ||
345 | dsp_tone(dsp, 0); | ||
346 | dsp_cmx_hardware(dsp->conf, dsp); | ||
347 | dsp_rx_off(dsp); | ||
348 | /* reset tx buffers (user space data) */ | ||
349 | tone_off: | ||
350 | dsp->rx_W = 0; | ||
351 | dsp->rx_R = 0; | ||
352 | break; | ||
353 | case DSP_VOL_CHANGE_TX: /* change volume */ | ||
354 | if (dsp->hdlc) { | ||
355 | ret = -EINVAL; | ||
356 | break; | ||
357 | } | ||
358 | if (len < sizeof(int)) { | ||
359 | ret = -EINVAL; | ||
360 | break; | ||
361 | } | ||
362 | dsp->tx_volume = *((int *)data); | ||
363 | if (dsp_debug & DEBUG_DSP_CORE) | ||
364 | printk(KERN_DEBUG "%s: change tx vol to %d\n", | ||
365 | __func__, dsp->tx_volume); | ||
366 | dsp_cmx_hardware(dsp->conf, dsp); | ||
367 | dsp_dtmf_hardware(dsp); | ||
368 | dsp_rx_off(dsp); | ||
369 | break; | ||
370 | case DSP_VOL_CHANGE_RX: /* change volume */ | ||
371 | if (dsp->hdlc) { | ||
372 | ret = -EINVAL; | ||
373 | break; | ||
374 | } | ||
375 | if (len < sizeof(int)) { | ||
376 | ret = -EINVAL; | ||
377 | break; | ||
378 | } | ||
379 | dsp->rx_volume = *((int *)data); | ||
380 | if (dsp_debug & DEBUG_DSP_CORE) | ||
381 | printk(KERN_DEBUG "%s: change rx vol to %d\n", | ||
382 | __func__, dsp->tx_volume); | ||
383 | dsp_cmx_hardware(dsp->conf, dsp); | ||
384 | dsp_dtmf_hardware(dsp); | ||
385 | dsp_rx_off(dsp); | ||
386 | break; | ||
387 | case DSP_ECHO_ON: /* enable echo */ | ||
388 | dsp->echo = 1; /* soft echo */ | ||
389 | if (dsp_debug & DEBUG_DSP_CORE) | ||
390 | printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); | ||
391 | dsp_cmx_hardware(dsp->conf, dsp); | ||
392 | dsp_rx_off(dsp); | ||
393 | if (dsp_debug & DEBUG_DSP_CMX) | ||
394 | dsp_cmx_debug(dsp); | ||
395 | break; | ||
396 | case DSP_ECHO_OFF: /* disable echo */ | ||
397 | dsp->echo = 0; | ||
398 | if (dsp_debug & DEBUG_DSP_CORE) | ||
399 | printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); | ||
400 | dsp_cmx_hardware(dsp->conf, dsp); | ||
401 | dsp_rx_off(dsp); | ||
402 | if (dsp_debug & DEBUG_DSP_CMX) | ||
403 | dsp_cmx_debug(dsp); | ||
404 | break; | ||
405 | case DSP_RECEIVE_ON: /* enable receive to user space */ | ||
406 | if (dsp_debug & DEBUG_DSP_CORE) | ||
407 | printk(KERN_DEBUG "%s: enable receive to user " | ||
408 | "space\n", __func__); | ||
409 | dsp->rx_disabled = 0; | ||
410 | dsp_rx_off(dsp); | ||
411 | break; | ||
412 | case DSP_RECEIVE_OFF: /* disable receive to user space */ | ||
413 | if (dsp_debug & DEBUG_DSP_CORE) | ||
414 | printk(KERN_DEBUG "%s: disable receive to " | ||
415 | "user space\n", __func__); | ||
416 | dsp->rx_disabled = 1; | ||
417 | dsp_rx_off(dsp); | ||
418 | break; | ||
419 | case DSP_MIX_ON: /* enable mixing of tx data */ | ||
420 | if (dsp->hdlc) { | ||
421 | ret = -EINVAL; | ||
422 | break; | ||
423 | } | ||
424 | if (dsp_debug & DEBUG_DSP_CORE) | ||
425 | printk(KERN_DEBUG "%s: enable mixing of " | ||
426 | "tx-data with conf mebers\n", __func__); | ||
427 | dsp->tx_mix = 1; | ||
428 | dsp_cmx_hardware(dsp->conf, dsp); | ||
429 | dsp_rx_off(dsp); | ||
430 | if (dsp_debug & DEBUG_DSP_CMX) | ||
431 | dsp_cmx_debug(dsp); | ||
432 | break; | ||
433 | case DSP_MIX_OFF: /* disable mixing of tx data */ | ||
434 | if (dsp->hdlc) { | ||
435 | ret = -EINVAL; | ||
436 | break; | ||
437 | } | ||
438 | if (dsp_debug & DEBUG_DSP_CORE) | ||
439 | printk(KERN_DEBUG "%s: disable mixing of " | ||
440 | "tx-data with conf mebers\n", __func__); | ||
441 | dsp->tx_mix = 0; | ||
442 | dsp_cmx_hardware(dsp->conf, dsp); | ||
443 | dsp_rx_off(dsp); | ||
444 | if (dsp_debug & DEBUG_DSP_CMX) | ||
445 | dsp_cmx_debug(dsp); | ||
446 | break; | ||
447 | case DSP_TXDATA_ON: /* enable txdata */ | ||
448 | dsp->tx_data = 1; | ||
449 | if (dsp_debug & DEBUG_DSP_CORE) | ||
450 | printk(KERN_DEBUG "%s: enable tx-data\n", __func__); | ||
451 | dsp_cmx_hardware(dsp->conf, dsp); | ||
452 | dsp_rx_off(dsp); | ||
453 | if (dsp_debug & DEBUG_DSP_CMX) | ||
454 | dsp_cmx_debug(dsp); | ||
455 | break; | ||
456 | case DSP_TXDATA_OFF: /* disable txdata */ | ||
457 | dsp->tx_data = 0; | ||
458 | if (dsp_debug & DEBUG_DSP_CORE) | ||
459 | printk(KERN_DEBUG "%s: disable tx-data\n", __func__); | ||
460 | dsp_cmx_hardware(dsp->conf, dsp); | ||
461 | dsp_rx_off(dsp); | ||
462 | if (dsp_debug & DEBUG_DSP_CMX) | ||
463 | dsp_cmx_debug(dsp); | ||
464 | break; | ||
465 | case DSP_DELAY: /* use delay algorithm instead of dynamic | ||
466 | jitter algorithm */ | ||
467 | if (dsp->hdlc) { | ||
468 | ret = -EINVAL; | ||
469 | break; | ||
470 | } | ||
471 | if (len < sizeof(int)) { | ||
472 | ret = -EINVAL; | ||
473 | break; | ||
474 | } | ||
475 | dsp->cmx_delay = (*((int *)data)) << 3; | ||
476 | /* miliseconds to samples */ | ||
477 | if (dsp->cmx_delay >= (CMX_BUFF_HALF>>1)) | ||
478 | /* clip to half of maximum usable buffer | ||
479 | (half of half buffer) */ | ||
480 | dsp->cmx_delay = (CMX_BUFF_HALF>>1) - 1; | ||
481 | if (dsp_debug & DEBUG_DSP_CORE) | ||
482 | printk(KERN_DEBUG "%s: use delay algorithm to " | ||
483 | "compensate jitter (%d samples)\n", | ||
484 | __func__, dsp->cmx_delay); | ||
485 | break; | ||
486 | case DSP_JITTER: /* use dynamic jitter algorithm instead of | ||
487 | delay algorithm */ | ||
488 | if (dsp->hdlc) { | ||
489 | ret = -EINVAL; | ||
490 | break; | ||
491 | } | ||
492 | dsp->cmx_delay = 0; | ||
493 | if (dsp_debug & DEBUG_DSP_CORE) | ||
494 | printk(KERN_DEBUG "%s: use jitter algorithm to " | ||
495 | "compensate jitter\n", __func__); | ||
496 | break; | ||
497 | case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */ | ||
498 | if (dsp->hdlc) { | ||
499 | ret = -EINVAL; | ||
500 | break; | ||
501 | } | ||
502 | dsp->tx_dejitter = 1; | ||
503 | if (dsp_debug & DEBUG_DSP_CORE) | ||
504 | printk(KERN_DEBUG "%s: use dejitter on TX " | ||
505 | "buffer\n", __func__); | ||
506 | break; | ||
507 | case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/ | ||
508 | if (dsp->hdlc) { | ||
509 | ret = -EINVAL; | ||
510 | break; | ||
511 | } | ||
512 | dsp->tx_dejitter = 0; | ||
513 | if (dsp_debug & DEBUG_DSP_CORE) | ||
514 | printk(KERN_DEBUG "%s: use TX buffer without " | ||
515 | "dejittering\n", __func__); | ||
516 | break; | ||
517 | case DSP_PIPELINE_CFG: | ||
518 | if (dsp->hdlc) { | ||
519 | ret = -EINVAL; | ||
520 | break; | ||
521 | } | ||
522 | if (len > 0 && ((char *)data)[len - 1]) { | ||
523 | printk(KERN_DEBUG "%s: pipeline config string " | ||
524 | "is not NULL terminated!\n", __func__); | ||
525 | ret = -EINVAL; | ||
526 | } else { | ||
527 | dsp->pipeline.inuse = 1; | ||
528 | dsp_cmx_hardware(dsp->conf, dsp); | ||
529 | ret = dsp_pipeline_build(&dsp->pipeline, | ||
530 | len > 0 ? (char *)data : NULL); | ||
531 | dsp_cmx_hardware(dsp->conf, dsp); | ||
532 | dsp_rx_off(dsp); | ||
533 | } | ||
534 | break; | ||
535 | case DSP_BF_ENABLE_KEY: /* turn blowfish on */ | ||
536 | if (dsp->hdlc) { | ||
537 | ret = -EINVAL; | ||
538 | break; | ||
539 | } | ||
540 | if (len < 4 || len > 56) { | ||
541 | ret = -EINVAL; | ||
542 | break; | ||
543 | } | ||
544 | if (dsp_debug & DEBUG_DSP_CORE) | ||
545 | printk(KERN_DEBUG "%s: turn blowfish on (key " | ||
546 | "not shown)\n", __func__); | ||
547 | ret = dsp_bf_init(dsp, (u8 *)data, len); | ||
548 | /* set new cont */ | ||
549 | if (!ret) | ||
550 | cont = DSP_BF_ACCEPT; | ||
551 | else | ||
552 | cont = DSP_BF_REJECT; | ||
553 | /* send indication if it worked to set it */ | ||
554 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY, | ||
555 | sizeof(int), &cont, GFP_ATOMIC); | ||
556 | if (nskb) { | ||
557 | if (dsp->up) { | ||
558 | if (dsp->up->send(dsp->up, nskb)) | ||
559 | dev_kfree_skb(nskb); | ||
560 | } else | ||
561 | dev_kfree_skb(nskb); | ||
562 | } | ||
563 | if (!ret) { | ||
564 | dsp_cmx_hardware(dsp->conf, dsp); | ||
565 | dsp_dtmf_hardware(dsp); | ||
566 | dsp_rx_off(dsp); | ||
567 | } | ||
568 | break; | ||
569 | case DSP_BF_DISABLE: /* turn blowfish off */ | ||
570 | if (dsp->hdlc) { | ||
571 | ret = -EINVAL; | ||
572 | break; | ||
573 | } | ||
574 | if (dsp_debug & DEBUG_DSP_CORE) | ||
575 | printk(KERN_DEBUG "%s: turn blowfish off\n", __func__); | ||
576 | dsp_bf_cleanup(dsp); | ||
577 | dsp_cmx_hardware(dsp->conf, dsp); | ||
578 | dsp_dtmf_hardware(dsp); | ||
579 | dsp_rx_off(dsp); | ||
580 | break; | ||
581 | default: | ||
582 | if (dsp_debug & DEBUG_DSP_CORE) | ||
583 | printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", | ||
584 | __func__, cont); | ||
585 | ret = -EINVAL; | ||
586 | } | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | static void | ||
591 | get_features(struct mISDNchannel *ch) | ||
592 | { | ||
593 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
594 | struct mISDN_ctrl_req cq; | ||
595 | |||
596 | if (dsp_options & DSP_OPT_NOHARDWARE) | ||
597 | return; | ||
598 | if (!ch->peer) { | ||
599 | if (dsp_debug & DEBUG_DSP_CORE) | ||
600 | printk(KERN_DEBUG "%s: no peer, no features\n", | ||
601 | __func__); | ||
602 | return; | ||
603 | } | ||
604 | memset(&cq, 0, sizeof(cq)); | ||
605 | cq.op = MISDN_CTRL_GETOP; | ||
606 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) { | ||
607 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
608 | __func__); | ||
609 | return; | ||
610 | } | ||
611 | if (cq.op & MISDN_CTRL_RX_OFF) | ||
612 | dsp->features_rx_off = 1; | ||
613 | if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { | ||
614 | cq.op = MISDN_CTRL_HW_FEATURES; | ||
615 | *((u_long *)&cq.p1) = (u_long)&dsp->features; | ||
616 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) { | ||
617 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", | ||
618 | __func__); | ||
619 | } | ||
620 | } else | ||
621 | if (dsp_debug & DEBUG_DSP_CORE) | ||
622 | printk(KERN_DEBUG "%s: features not supported for %s\n", | ||
623 | __func__, dsp->name); | ||
624 | } | ||
625 | |||
626 | static int | ||
627 | dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) | ||
628 | { | ||
629 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
630 | struct mISDNhead *hh; | ||
631 | int ret = 0; | ||
632 | u8 *digits; | ||
633 | int cont; | ||
634 | struct sk_buff *nskb; | ||
635 | u_long flags; | ||
636 | |||
637 | hh = mISDN_HEAD_P(skb); | ||
638 | switch (hh->prim) { | ||
639 | /* FROM DOWN */ | ||
640 | case (PH_DATA_CNF): | ||
641 | dsp->data_pending = 0; | ||
642 | /* trigger next hdlc frame, if any */ | ||
643 | if (dsp->hdlc) { | ||
644 | spin_lock_irqsave(&dsp_lock, flags); | ||
645 | if (dsp->b_active) | ||
646 | schedule_work(&dsp->workq); | ||
647 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
648 | } | ||
649 | break; | ||
650 | case (PH_DATA_IND): | ||
651 | case (DL_DATA_IND): | ||
652 | if (skb->len < 1) { | ||
653 | ret = -EINVAL; | ||
654 | break; | ||
655 | } | ||
656 | if (dsp->rx_is_off) { | ||
657 | if (dsp_debug & DEBUG_DSP_CORE) | ||
658 | printk(KERN_DEBUG "%s: rx-data during rx_off" | ||
659 | " for %s\n", | ||
660 | __func__, dsp->name); | ||
661 | } | ||
662 | if (dsp->hdlc) { | ||
663 | /* hdlc */ | ||
664 | spin_lock_irqsave(&dsp_lock, flags); | ||
665 | dsp_cmx_hdlc(dsp, skb); | ||
666 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
667 | if (dsp->rx_disabled) { | ||
668 | /* if receive is not allowed */ | ||
669 | break; | ||
670 | } | ||
671 | hh->prim = DL_DATA_IND; | ||
672 | if (dsp->up) | ||
673 | return dsp->up->send(dsp->up, skb); | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | /* decrypt if enabled */ | ||
678 | if (dsp->bf_enable) | ||
679 | dsp_bf_decrypt(dsp, skb->data, skb->len); | ||
680 | /* pipeline */ | ||
681 | if (dsp->pipeline.inuse) | ||
682 | dsp_pipeline_process_rx(&dsp->pipeline, skb->data, | ||
683 | skb->len); | ||
684 | /* change volume if requested */ | ||
685 | if (dsp->rx_volume) | ||
686 | dsp_change_volume(skb, dsp->rx_volume); | ||
687 | |||
688 | /* check if dtmf soft decoding is turned on */ | ||
689 | if (dsp->dtmf.software) { | ||
690 | digits = dsp_dtmf_goertzel_decode(dsp, skb->data, | ||
691 | skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); | ||
692 | while (*digits) { | ||
693 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
694 | printk(KERN_DEBUG "%s: digit" | ||
695 | "(%c) to layer %s\n", | ||
696 | __func__, *digits, dsp->name); | ||
697 | cont = DTMF_TONE_VAL | *digits; | ||
698 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, | ||
699 | MISDN_ID_ANY, sizeof(int), &cont, | ||
700 | GFP_ATOMIC); | ||
701 | if (nskb) { | ||
702 | if (dsp->up) { | ||
703 | if (dsp->up->send( | ||
704 | dsp->up, nskb)) | ||
705 | dev_kfree_skb(nskb); | ||
706 | } else | ||
707 | dev_kfree_skb(nskb); | ||
708 | } | ||
709 | digits++; | ||
710 | } | ||
711 | } | ||
712 | /* we need to process receive data if software */ | ||
713 | spin_lock_irqsave(&dsp_lock, flags); | ||
714 | if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { | ||
715 | /* process data from card at cmx */ | ||
716 | dsp_cmx_receive(dsp, skb); | ||
717 | } | ||
718 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
719 | |||
720 | if (dsp->rx_disabled) { | ||
721 | /* if receive is not allowed */ | ||
722 | break; | ||
723 | } | ||
724 | hh->prim = DL_DATA_IND; | ||
725 | if (dsp->up) | ||
726 | return dsp->up->send(dsp->up, skb); | ||
727 | break; | ||
728 | case (PH_CONTROL_IND): | ||
729 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
730 | printk(KERN_DEBUG "%s: PH_CONTROL INDICATION " | ||
731 | "received: %x (len %d) %s\n", __func__, | ||
732 | hh->id, skb->len, dsp->name); | ||
733 | switch (hh->id) { | ||
734 | case (DTMF_HFC_COEF): /* getting coefficients */ | ||
735 | if (!dsp->dtmf.hardware) { | ||
736 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
737 | printk(KERN_DEBUG "%s: ignoring DTMF " | ||
738 | "coefficients from HFC\n", | ||
739 | __func__); | ||
740 | break; | ||
741 | } | ||
742 | digits = dsp_dtmf_goertzel_decode(dsp, skb->data, | ||
743 | skb->len, 2); | ||
744 | while (*digits) { | ||
745 | int k; | ||
746 | struct sk_buff *nskb; | ||
747 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
748 | printk(KERN_DEBUG "%s: digit" | ||
749 | "(%c) to layer %s\n", | ||
750 | __func__, *digits, dsp->name); | ||
751 | k = *digits | DTMF_TONE_VAL; | ||
752 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, | ||
753 | MISDN_ID_ANY, sizeof(int), &k, | ||
754 | GFP_ATOMIC); | ||
755 | if (nskb) { | ||
756 | if (dsp->up) { | ||
757 | if (dsp->up->send( | ||
758 | dsp->up, nskb)) | ||
759 | dev_kfree_skb(nskb); | ||
760 | } else | ||
761 | dev_kfree_skb(nskb); | ||
762 | } | ||
763 | digits++; | ||
764 | } | ||
765 | break; | ||
766 | case (HFC_VOL_CHANGE_TX): /* change volume */ | ||
767 | if (skb->len != sizeof(int)) { | ||
768 | ret = -EINVAL; | ||
769 | break; | ||
770 | } | ||
771 | spin_lock_irqsave(&dsp_lock, flags); | ||
772 | dsp->tx_volume = *((int *)skb->data); | ||
773 | if (dsp_debug & DEBUG_DSP_CORE) | ||
774 | printk(KERN_DEBUG "%s: change tx volume to " | ||
775 | "%d\n", __func__, dsp->tx_volume); | ||
776 | dsp_cmx_hardware(dsp->conf, dsp); | ||
777 | dsp_dtmf_hardware(dsp); | ||
778 | dsp_rx_off(dsp); | ||
779 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
780 | break; | ||
781 | default: | ||
782 | if (dsp_debug & DEBUG_DSP_CORE) | ||
783 | printk(KERN_DEBUG "%s: ctrl ind %x unhandled " | ||
784 | "%s\n", __func__, hh->id, dsp->name); | ||
785 | ret = -EINVAL; | ||
786 | } | ||
787 | break; | ||
788 | case (PH_ACTIVATE_IND): | ||
789 | case (PH_ACTIVATE_CNF): | ||
790 | if (dsp_debug & DEBUG_DSP_CORE) | ||
791 | printk(KERN_DEBUG "%s: b_channel is now active %s\n", | ||
792 | __func__, dsp->name); | ||
793 | /* bchannel now active */ | ||
794 | spin_lock_irqsave(&dsp_lock, flags); | ||
795 | dsp->b_active = 1; | ||
796 | dsp->data_pending = 0; | ||
797 | dsp->rx_init = 1; | ||
798 | /* rx_W and rx_R will be adjusted on first frame */ | ||
799 | dsp->rx_W = 0; | ||
800 | dsp->rx_R = 0; | ||
801 | memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff)); | ||
802 | dsp_cmx_hardware(dsp->conf, dsp); | ||
803 | dsp_dtmf_hardware(dsp); | ||
804 | dsp_rx_off(dsp); | ||
805 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
806 | if (dsp_debug & DEBUG_DSP_CORE) | ||
807 | printk(KERN_DEBUG "%s: done with activation, sending " | ||
808 | "confirm to user space. %s\n", __func__, | ||
809 | dsp->name); | ||
810 | /* send activation to upper layer */ | ||
811 | hh->prim = DL_ESTABLISH_CNF; | ||
812 | if (dsp->up) | ||
813 | return dsp->up->send(dsp->up, skb); | ||
814 | break; | ||
815 | case (PH_DEACTIVATE_IND): | ||
816 | case (PH_DEACTIVATE_CNF): | ||
817 | if (dsp_debug & DEBUG_DSP_CORE) | ||
818 | printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", | ||
819 | __func__, dsp->name); | ||
820 | /* bchannel now inactive */ | ||
821 | spin_lock_irqsave(&dsp_lock, flags); | ||
822 | dsp->b_active = 0; | ||
823 | dsp->data_pending = 0; | ||
824 | dsp_cmx_hardware(dsp->conf, dsp); | ||
825 | dsp_rx_off(dsp); | ||
826 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
827 | hh->prim = DL_RELEASE_CNF; | ||
828 | if (dsp->up) | ||
829 | return dsp->up->send(dsp->up, skb); | ||
830 | break; | ||
831 | /* FROM UP */ | ||
832 | case (DL_DATA_REQ): | ||
833 | case (PH_DATA_REQ): | ||
834 | if (skb->len < 1) { | ||
835 | ret = -EINVAL; | ||
836 | break; | ||
837 | } | ||
838 | if (dsp->hdlc) { | ||
839 | /* hdlc */ | ||
840 | spin_lock_irqsave(&dsp_lock, flags); | ||
841 | if (dsp->b_active) { | ||
842 | skb_queue_tail(&dsp->sendq, skb); | ||
843 | schedule_work(&dsp->workq); | ||
844 | } | ||
845 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
846 | return 0; | ||
847 | } | ||
848 | /* send data to tx-buffer (if no tone is played) */ | ||
849 | if (!dsp->tone.tone) { | ||
850 | spin_lock_irqsave(&dsp_lock, flags); | ||
851 | dsp_cmx_transmit(dsp, skb); | ||
852 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
853 | } | ||
854 | break; | ||
855 | case (PH_CONTROL_REQ): | ||
856 | spin_lock_irqsave(&dsp_lock, flags); | ||
857 | ret = dsp_control_req(dsp, hh, skb); | ||
858 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
859 | break; | ||
860 | case (DL_ESTABLISH_REQ): | ||
861 | case (PH_ACTIVATE_REQ): | ||
862 | if (dsp_debug & DEBUG_DSP_CORE) | ||
863 | printk(KERN_DEBUG "%s: activating b_channel %s\n", | ||
864 | __func__, dsp->name); | ||
865 | if (dsp->dtmf.hardware || dsp->dtmf.software) | ||
866 | dsp_dtmf_goertzel_init(dsp); | ||
867 | get_features(ch); | ||
868 | /* send ph_activate */ | ||
869 | hh->prim = PH_ACTIVATE_REQ; | ||
870 | if (ch->peer) | ||
871 | return ch->recv(ch->peer, skb); | ||
872 | break; | ||
873 | case (DL_RELEASE_REQ): | ||
874 | case (PH_DEACTIVATE_REQ): | ||
875 | if (dsp_debug & DEBUG_DSP_CORE) | ||
876 | printk(KERN_DEBUG "%s: releasing b_channel %s\n", | ||
877 | __func__, dsp->name); | ||
878 | spin_lock_irqsave(&dsp_lock, flags); | ||
879 | dsp->tone.tone = 0; | ||
880 | dsp->tone.hardware = 0; | ||
881 | dsp->tone.software = 0; | ||
882 | if (timer_pending(&dsp->tone.tl)) | ||
883 | del_timer(&dsp->tone.tl); | ||
884 | if (dsp->conf) | ||
885 | dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be | ||
886 | called here */ | ||
887 | skb_queue_purge(&dsp->sendq); | ||
888 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
889 | hh->prim = PH_DEACTIVATE_REQ; | ||
890 | if (ch->peer) | ||
891 | return ch->recv(ch->peer, skb); | ||
892 | break; | ||
893 | default: | ||
894 | if (dsp_debug & DEBUG_DSP_CORE) | ||
895 | printk(KERN_DEBUG "%s: msg %x unhandled %s\n", | ||
896 | __func__, hh->prim, dsp->name); | ||
897 | ret = -EINVAL; | ||
898 | } | ||
899 | if (!ret) | ||
900 | dev_kfree_skb(skb); | ||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | static int | ||
905 | dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
906 | { | ||
907 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
908 | u_long flags; | ||
909 | int err = 0; | ||
910 | |||
911 | if (debug & DEBUG_DSP_CTRL) | ||
912 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
913 | |||
914 | switch (cmd) { | ||
915 | case OPEN_CHANNEL: | ||
916 | break; | ||
917 | case CLOSE_CHANNEL: | ||
918 | if (dsp->ch.peer) | ||
919 | dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL); | ||
920 | |||
921 | /* wait until workqueue has finished, | ||
922 | * must lock here, or we may hit send-process currently | ||
923 | * queueing. */ | ||
924 | spin_lock_irqsave(&dsp_lock, flags); | ||
925 | dsp->b_active = 0; | ||
926 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
927 | /* MUST not be locked, because it waits until queue is done. */ | ||
928 | cancel_work_sync(&dsp->workq); | ||
929 | spin_lock_irqsave(&dsp_lock, flags); | ||
930 | if (timer_pending(&dsp->tone.tl)) | ||
931 | del_timer(&dsp->tone.tl); | ||
932 | skb_queue_purge(&dsp->sendq); | ||
933 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
934 | printk(KERN_DEBUG "%s: releasing member %s\n", | ||
935 | __func__, dsp->name); | ||
936 | dsp->b_active = 0; | ||
937 | dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called | ||
938 | here */ | ||
939 | dsp_pipeline_destroy(&dsp->pipeline); | ||
940 | |||
941 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
942 | printk(KERN_DEBUG "%s: remove & destroy object %s\n", | ||
943 | __func__, dsp->name); | ||
944 | list_del(&dsp->list); | ||
945 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
946 | |||
947 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
948 | printk(KERN_DEBUG "%s: dsp instance released\n", | ||
949 | __func__); | ||
950 | vfree(dsp); | ||
951 | module_put(THIS_MODULE); | ||
952 | break; | ||
953 | } | ||
954 | return err; | ||
955 | } | ||
956 | |||
957 | static void | ||
958 | dsp_send_bh(struct work_struct *work) | ||
959 | { | ||
960 | struct dsp *dsp = container_of(work, struct dsp, workq); | ||
961 | struct sk_buff *skb; | ||
962 | struct mISDNhead *hh; | ||
963 | |||
964 | if (dsp->hdlc && dsp->data_pending) | ||
965 | return; /* wait until data has been acknowledged */ | ||
966 | |||
967 | /* send queued data */ | ||
968 | while ((skb = skb_dequeue(&dsp->sendq))) { | ||
969 | /* in locked date, we must have still data in queue */ | ||
970 | if (dsp->data_pending) { | ||
971 | if (dsp_debug & DEBUG_DSP_CORE) | ||
972 | printk(KERN_DEBUG "%s: fifo full %s, this is " | ||
973 | "no bug!\n", __func__, dsp->name); | ||
974 | /* flush transparent data, if not acked */ | ||
975 | dev_kfree_skb(skb); | ||
976 | continue; | ||
977 | } | ||
978 | hh = mISDN_HEAD_P(skb); | ||
979 | if (hh->prim == DL_DATA_REQ) { | ||
980 | /* send packet up */ | ||
981 | if (dsp->up) { | ||
982 | if (dsp->up->send(dsp->up, skb)) | ||
983 | dev_kfree_skb(skb); | ||
984 | } else | ||
985 | dev_kfree_skb(skb); | ||
986 | } else { | ||
987 | /* send packet down */ | ||
988 | if (dsp->ch.peer) { | ||
989 | dsp->data_pending = 1; | ||
990 | if (dsp->ch.recv(dsp->ch.peer, skb)) { | ||
991 | dev_kfree_skb(skb); | ||
992 | dsp->data_pending = 0; | ||
993 | } | ||
994 | } else | ||
995 | dev_kfree_skb(skb); | ||
996 | } | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | static int | ||
1001 | dspcreate(struct channel_req *crq) | ||
1002 | { | ||
1003 | struct dsp *ndsp; | ||
1004 | u_long flags; | ||
1005 | |||
1006 | if (crq->protocol != ISDN_P_B_L2DSP | ||
1007 | && crq->protocol != ISDN_P_B_L2DSPHDLC) | ||
1008 | return -EPROTONOSUPPORT; | ||
1009 | ndsp = vmalloc(sizeof(struct dsp)); | ||
1010 | if (!ndsp) { | ||
1011 | printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__); | ||
1012 | return -ENOMEM; | ||
1013 | } | ||
1014 | memset(ndsp, 0, sizeof(struct dsp)); | ||
1015 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
1016 | printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__); | ||
1017 | |||
1018 | /* default enabled */ | ||
1019 | INIT_WORK(&ndsp->workq, (void *)dsp_send_bh); | ||
1020 | skb_queue_head_init(&ndsp->sendq); | ||
1021 | ndsp->ch.send = dsp_function; | ||
1022 | ndsp->ch.ctrl = dsp_ctrl; | ||
1023 | ndsp->up = crq->ch; | ||
1024 | crq->ch = &ndsp->ch; | ||
1025 | if (crq->protocol == ISDN_P_B_L2DSP) { | ||
1026 | crq->protocol = ISDN_P_B_RAW; | ||
1027 | ndsp->hdlc = 0; | ||
1028 | } else { | ||
1029 | crq->protocol = ISDN_P_B_HDLC; | ||
1030 | ndsp->hdlc = 1; | ||
1031 | } | ||
1032 | if (!try_module_get(THIS_MODULE)) | ||
1033 | printk(KERN_WARNING "%s:cannot get module\n", | ||
1034 | __func__); | ||
1035 | |||
1036 | sprintf(ndsp->name, "DSP_C%x(0x%p)", | ||
1037 | ndsp->up->st->dev->id + 1, ndsp); | ||
1038 | /* set frame size to start */ | ||
1039 | ndsp->features.hfc_id = -1; /* current PCM id */ | ||
1040 | ndsp->features.pcm_id = -1; /* current PCM id */ | ||
1041 | ndsp->pcm_slot_rx = -1; /* current CPM slot */ | ||
1042 | ndsp->pcm_slot_tx = -1; | ||
1043 | ndsp->pcm_bank_rx = -1; | ||
1044 | ndsp->pcm_bank_tx = -1; | ||
1045 | ndsp->hfc_conf = -1; /* current conference number */ | ||
1046 | /* set tone timer */ | ||
1047 | ndsp->tone.tl.function = (void *)dsp_tone_timeout; | ||
1048 | ndsp->tone.tl.data = (long) ndsp; | ||
1049 | init_timer(&ndsp->tone.tl); | ||
1050 | |||
1051 | if (dtmfthreshold < 20 || dtmfthreshold > 500) | ||
1052 | dtmfthreshold = 200; | ||
1053 | ndsp->dtmf.treshold = dtmfthreshold*10000; | ||
1054 | |||
1055 | /* init pipeline append to list */ | ||
1056 | spin_lock_irqsave(&dsp_lock, flags); | ||
1057 | dsp_pipeline_init(&ndsp->pipeline); | ||
1058 | list_add_tail(&ndsp->list, &dsp_ilist); | ||
1059 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | static struct Bprotocol DSP = { | ||
1066 | .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK)) | ||
1067 | | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), | ||
1068 | .name = "dsp", | ||
1069 | .create = dspcreate | ||
1070 | }; | ||
1071 | |||
1072 | static int dsp_init(void) | ||
1073 | { | ||
1074 | int err; | ||
1075 | int tics; | ||
1076 | |||
1077 | printk(KERN_INFO "DSP modul %s\n", mISDN_dsp_revision); | ||
1078 | |||
1079 | dsp_options = options; | ||
1080 | dsp_debug = debug; | ||
1081 | |||
1082 | /* set packet size */ | ||
1083 | dsp_poll = poll; | ||
1084 | if (dsp_poll) { | ||
1085 | if (dsp_poll > MAX_POLL) { | ||
1086 | printk(KERN_ERR "%s: Wrong poll value (%d), use %d " | ||
1087 | "maximum.\n", __func__, poll, MAX_POLL); | ||
1088 | err = -EINVAL; | ||
1089 | return err; | ||
1090 | } | ||
1091 | if (dsp_poll < 8) { | ||
1092 | printk(KERN_ERR "%s: Wrong poll value (%d), use 8 " | ||
1093 | "minimum.\n", __func__, dsp_poll); | ||
1094 | err = -EINVAL; | ||
1095 | return err; | ||
1096 | } | ||
1097 | dsp_tics = poll * HZ / 8000; | ||
1098 | if (dsp_tics * 8000 != poll * HZ) { | ||
1099 | printk(KERN_INFO "mISDN_dsp: Cannot clock every %d " | ||
1100 | "samples (0,125 ms). It is not a multiple of " | ||
1101 | "%d HZ.\n", poll, HZ); | ||
1102 | err = -EINVAL; | ||
1103 | return err; | ||
1104 | } | ||
1105 | } else { | ||
1106 | poll = 8; | ||
1107 | while (poll <= MAX_POLL) { | ||
1108 | tics = poll * HZ / 8000; | ||
1109 | if (tics * 8000 == poll * HZ) { | ||
1110 | dsp_tics = tics; | ||
1111 | dsp_poll = poll; | ||
1112 | if (poll >= 64) | ||
1113 | break; | ||
1114 | } | ||
1115 | poll++; | ||
1116 | } | ||
1117 | } | ||
1118 | if (dsp_poll == 0) { | ||
1119 | printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel " | ||
1120 | "clock that equals exactly the duration of 8-256 " | ||
1121 | "samples. (Choose kernel clock speed like 100, 250, " | ||
1122 | "300, 1000)\n"); | ||
1123 | err = -EINVAL; | ||
1124 | return err; | ||
1125 | } | ||
1126 | printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals " | ||
1127 | "%d jiffies.\n", dsp_poll, dsp_tics); | ||
1128 | |||
1129 | spin_lock_init(&dsp_lock); | ||
1130 | INIT_LIST_HEAD(&dsp_ilist); | ||
1131 | INIT_LIST_HEAD(&conf_ilist); | ||
1132 | |||
1133 | /* init conversion tables */ | ||
1134 | dsp_audio_generate_law_tables(); | ||
1135 | dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a; | ||
1136 | dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32: | ||
1137 | dsp_audio_alaw_to_s32; | ||
1138 | dsp_audio_generate_s2law_table(); | ||
1139 | dsp_audio_generate_seven(); | ||
1140 | dsp_audio_generate_mix_table(); | ||
1141 | if (dsp_options & DSP_OPT_ULAW) | ||
1142 | dsp_audio_generate_ulaw_samples(); | ||
1143 | dsp_audio_generate_volume_changes(); | ||
1144 | |||
1145 | err = dsp_pipeline_module_init(); | ||
1146 | if (err) { | ||
1147 | printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, " | ||
1148 | "error(%d)\n", err); | ||
1149 | return err; | ||
1150 | } | ||
1151 | |||
1152 | err = mISDN_register_Bprotocol(&DSP); | ||
1153 | if (err) { | ||
1154 | printk(KERN_ERR "Can't register %s error(%d)\n", DSP.name, err); | ||
1155 | return err; | ||
1156 | } | ||
1157 | |||
1158 | /* set sample timer */ | ||
1159 | dsp_spl_tl.function = (void *)dsp_cmx_send; | ||
1160 | dsp_spl_tl.data = 0; | ||
1161 | init_timer(&dsp_spl_tl); | ||
1162 | dsp_spl_tl.expires = jiffies + dsp_tics; | ||
1163 | dsp_spl_jiffies = dsp_spl_tl.expires; | ||
1164 | add_timer(&dsp_spl_tl); | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | static void dsp_cleanup(void) | ||
1171 | { | ||
1172 | mISDN_unregister_Bprotocol(&DSP); | ||
1173 | |||
1174 | if (timer_pending(&dsp_spl_tl)) | ||
1175 | del_timer(&dsp_spl_tl); | ||
1176 | |||
1177 | if (!list_empty(&dsp_ilist)) { | ||
1178 | printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " | ||
1179 | "empty.\n"); | ||
1180 | } | ||
1181 | if (!list_empty(&conf_ilist)) { | ||
1182 | printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not " | ||
1183 | "all memory freed.\n"); | ||
1184 | } | ||
1185 | |||
1186 | dsp_pipeline_module_exit(); | ||
1187 | } | ||
1188 | |||
1189 | module_init(dsp_init); | ||
1190 | module_exit(dsp_cleanup); | ||
1191 | |||
diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c new file mode 100644 index 000000000000..efc371c1f0dc --- /dev/null +++ b/drivers/isdn/mISDN/dsp_dtmf.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * DTMF decoder. | ||
3 | * | ||
4 | * Copyright by Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * based on different decoders such as ISDN4Linux | ||
6 | * | ||
7 | * This software may be used and distributed according to the terms | ||
8 | * of the GNU General Public License, incorporated herein by reference. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/mISDNif.h> | ||
13 | #include <linux/mISDNdsp.h> | ||
14 | #include "core.h" | ||
15 | #include "dsp.h" | ||
16 | |||
17 | #define NCOEFF 8 /* number of frequencies to be analyzed */ | ||
18 | |||
19 | /* For DTMF recognition: | ||
20 | * 2 * cos(2 * PI * k / N) precalculated for all k | ||
21 | */ | ||
22 | static u64 cos2pik[NCOEFF] = | ||
23 | { | ||
24 | /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */ | ||
25 | 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630 | ||
26 | }; | ||
27 | |||
28 | /* digit matrix */ | ||
29 | static char dtmf_matrix[4][4] = | ||
30 | { | ||
31 | {'1', '2', '3', 'A'}, | ||
32 | {'4', '5', '6', 'B'}, | ||
33 | {'7', '8', '9', 'C'}, | ||
34 | {'*', '0', '#', 'D'} | ||
35 | }; | ||
36 | |||
37 | /* dtmf detection using goertzel algorithm | ||
38 | * init function | ||
39 | */ | ||
40 | void dsp_dtmf_goertzel_init(struct dsp *dsp) | ||
41 | { | ||
42 | dsp->dtmf.size = 0; | ||
43 | dsp->dtmf.lastwhat = '\0'; | ||
44 | dsp->dtmf.lastdigit = '\0'; | ||
45 | dsp->dtmf.count = 0; | ||
46 | } | ||
47 | |||
48 | /* check for hardware or software features | ||
49 | */ | ||
50 | void dsp_dtmf_hardware(struct dsp *dsp) | ||
51 | { | ||
52 | int hardware = 1; | ||
53 | |||
54 | if (!dsp->features.hfc_dtmf) | ||
55 | hardware = 0; | ||
56 | |||
57 | /* check for volume change */ | ||
58 | if (dsp->tx_volume) { | ||
59 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
60 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
61 | "because tx_volume is changed\n", | ||
62 | __func__, dsp->name); | ||
63 | hardware = 0; | ||
64 | } | ||
65 | if (dsp->rx_volume) { | ||
66 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
67 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
68 | "because rx_volume is changed\n", | ||
69 | __func__, dsp->name); | ||
70 | hardware = 0; | ||
71 | } | ||
72 | /* check if encryption is enabled */ | ||
73 | if (dsp->bf_enable) { | ||
74 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
75 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
76 | "because encryption is enabled\n", | ||
77 | __func__, dsp->name); | ||
78 | hardware = 0; | ||
79 | } | ||
80 | /* check if pipeline exists */ | ||
81 | if (dsp->pipeline.inuse) { | ||
82 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
83 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
84 | "because pipeline exists.\n", | ||
85 | __func__, dsp->name); | ||
86 | hardware = 0; | ||
87 | } | ||
88 | |||
89 | dsp->dtmf.hardware = hardware; | ||
90 | dsp->dtmf.software = !hardware; | ||
91 | } | ||
92 | |||
93 | |||
94 | /************************************************************* | ||
95 | * calculate the coefficients of the given sample and decode * | ||
96 | *************************************************************/ | ||
97 | |||
98 | /* the given sample is decoded. if the sample is not long enough for a | ||
99 | * complete frame, the decoding is finished and continued with the next | ||
100 | * call of this function. | ||
101 | * | ||
102 | * the algorithm is very good for detection with a minimum of errors. i | ||
103 | * tested it allot. it even works with very short tones (40ms). the only | ||
104 | * disadvantage is, that it doesn't work good with different volumes of both | ||
105 | * tones. this will happen, if accoustically coupled dialers are used. | ||
106 | * it sometimes detects tones during speach, which is normal for decoders. | ||
107 | * use sequences to given commands during calls. | ||
108 | * | ||
109 | * dtmf - points to a structure of the current dtmf state | ||
110 | * spl and len - the sample | ||
111 | * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder | ||
112 | */ | ||
113 | |||
114 | u8 | ||
115 | *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt) | ||
116 | { | ||
117 | u8 what; | ||
118 | int size; | ||
119 | signed short *buf; | ||
120 | s32 sk, sk1, sk2; | ||
121 | int k, n, i; | ||
122 | s32 *hfccoeff; | ||
123 | s32 result[NCOEFF], tresh, treshl; | ||
124 | int lowgroup, highgroup; | ||
125 | s64 cos2pik_; | ||
126 | |||
127 | dsp->dtmf.digits[0] = '\0'; | ||
128 | |||
129 | /* Note: The function will loop until the buffer has not enough samples | ||
130 | * left to decode a full frame. | ||
131 | */ | ||
132 | again: | ||
133 | /* convert samples */ | ||
134 | size = dsp->dtmf.size; | ||
135 | buf = dsp->dtmf.buffer; | ||
136 | switch (fmt) { | ||
137 | case 0: /* alaw */ | ||
138 | case 1: /* ulaw */ | ||
139 | while (size < DSP_DTMF_NPOINTS && len) { | ||
140 | buf[size++] = dsp_audio_law_to_s32[*data++]; | ||
141 | len--; | ||
142 | } | ||
143 | break; | ||
144 | |||
145 | case 2: /* HFC coefficients */ | ||
146 | default: | ||
147 | if (len < 64) { | ||
148 | if (len > 0) | ||
149 | printk(KERN_ERR "%s: coefficients have invalid " | ||
150 | "size. (is=%d < must=%d)\n", | ||
151 | __func__, len, 64); | ||
152 | return dsp->dtmf.digits; | ||
153 | } | ||
154 | hfccoeff = (s32 *)data; | ||
155 | for (k = 0; k < NCOEFF; k++) { | ||
156 | sk2 = (*hfccoeff++)>>4; | ||
157 | sk = (*hfccoeff++)>>4; | ||
158 | if (sk > 32767 || sk < -32767 || sk2 > 32767 | ||
159 | || sk2 < -32767) | ||
160 | printk(KERN_WARNING | ||
161 | "DTMF-Detection overflow\n"); | ||
162 | /* compute |X(k)|**2 */ | ||
163 | result[k] = | ||
164 | (sk * sk) - | ||
165 | (((cos2pik[k] * sk) >> 15) * sk2) + | ||
166 | (sk2 * sk2); | ||
167 | } | ||
168 | data += 64; | ||
169 | len -= 64; | ||
170 | goto coefficients; | ||
171 | break; | ||
172 | } | ||
173 | dsp->dtmf.size = size; | ||
174 | |||
175 | if (size < DSP_DTMF_NPOINTS) | ||
176 | return dsp->dtmf.digits; | ||
177 | |||
178 | dsp->dtmf.size = 0; | ||
179 | |||
180 | /* now we have a full buffer of signed long samples - we do goertzel */ | ||
181 | for (k = 0; k < NCOEFF; k++) { | ||
182 | sk = 0; | ||
183 | sk1 = 0; | ||
184 | sk2 = 0; | ||
185 | buf = dsp->dtmf.buffer; | ||
186 | cos2pik_ = cos2pik[k]; | ||
187 | for (n = 0; n < DSP_DTMF_NPOINTS; n++) { | ||
188 | sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++); | ||
189 | sk2 = sk1; | ||
190 | sk1 = sk; | ||
191 | } | ||
192 | sk >>= 8; | ||
193 | sk2 >>= 8; | ||
194 | if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767) | ||
195 | printk(KERN_WARNING "DTMF-Detection overflow\n"); | ||
196 | /* compute |X(k)|**2 */ | ||
197 | result[k] = | ||
198 | (sk * sk) - | ||
199 | (((cos2pik[k] * sk) >> 15) * sk2) + | ||
200 | (sk2 * sk2); | ||
201 | } | ||
202 | |||
203 | /* our (squared) coefficients have been calculated, we need to process | ||
204 | * them. | ||
205 | */ | ||
206 | coefficients: | ||
207 | tresh = 0; | ||
208 | for (i = 0; i < NCOEFF; i++) { | ||
209 | if (result[i] < 0) | ||
210 | result[i] = 0; | ||
211 | if (result[i] > dsp->dtmf.treshold) { | ||
212 | if (result[i] > tresh) | ||
213 | tresh = result[i]; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (tresh == 0) { | ||
218 | what = 0; | ||
219 | goto storedigit; | ||
220 | } | ||
221 | |||
222 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
223 | printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" | ||
224 | " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", | ||
225 | result[0]/10000, result[1]/10000, result[2]/10000, | ||
226 | result[3]/10000, result[4]/10000, result[5]/10000, | ||
227 | result[6]/10000, result[7]/10000, tresh/10000, | ||
228 | result[0]/(tresh/100), result[1]/(tresh/100), | ||
229 | result[2]/(tresh/100), result[3]/(tresh/100), | ||
230 | result[4]/(tresh/100), result[5]/(tresh/100), | ||
231 | result[6]/(tresh/100), result[7]/(tresh/100)); | ||
232 | |||
233 | /* calc digit (lowgroup/highgroup) */ | ||
234 | lowgroup = -1; | ||
235 | highgroup = -1; | ||
236 | treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */ | ||
237 | tresh = tresh >> 2; /* touchtones must match within 6 dB */ | ||
238 | for (i = 0; i < NCOEFF; i++) { | ||
239 | if (result[i] < treshl) | ||
240 | continue; /* ignore */ | ||
241 | if (result[i] < tresh) { | ||
242 | lowgroup = -1; | ||
243 | highgroup = -1; | ||
244 | break; /* noise inbetween */ | ||
245 | } | ||
246 | /* good level found. This is allowed only one time per group */ | ||
247 | if (i < NCOEFF/2) { | ||
248 | /* lowgroup */ | ||
249 | if (lowgroup >= 0) { | ||
250 | /* Bad. Another tone found. */ | ||
251 | lowgroup = -1; | ||
252 | break; | ||
253 | } else | ||
254 | lowgroup = i; | ||
255 | } else { | ||
256 | /* higroup */ | ||
257 | if (highgroup >= 0) { | ||
258 | /* Bad. Another tone found. */ | ||
259 | highgroup = -1; | ||
260 | break; | ||
261 | } else | ||
262 | highgroup = i-(NCOEFF/2); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* get digit or null */ | ||
267 | what = 0; | ||
268 | if (lowgroup >= 0 && highgroup >= 0) | ||
269 | what = dtmf_matrix[lowgroup][highgroup]; | ||
270 | |||
271 | storedigit: | ||
272 | if (what && (dsp_debug & DEBUG_DSP_DTMF)) | ||
273 | printk(KERN_DEBUG "DTMF what: %c\n", what); | ||
274 | |||
275 | if (dsp->dtmf.lastwhat != what) | ||
276 | dsp->dtmf.count = 0; | ||
277 | |||
278 | /* the tone (or no tone) must remain 3 times without change */ | ||
279 | if (dsp->dtmf.count == 2) { | ||
280 | if (dsp->dtmf.lastdigit != what) { | ||
281 | dsp->dtmf.lastdigit = what; | ||
282 | if (what) { | ||
283 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
284 | printk(KERN_DEBUG "DTMF digit: %c\n", | ||
285 | what); | ||
286 | if ((strlen(dsp->dtmf.digits)+1) | ||
287 | < sizeof(dsp->dtmf.digits)) { | ||
288 | dsp->dtmf.digits[strlen( | ||
289 | dsp->dtmf.digits)+1] = '\0'; | ||
290 | dsp->dtmf.digits[strlen( | ||
291 | dsp->dtmf.digits)] = what; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } else | ||
296 | dsp->dtmf.count++; | ||
297 | |||
298 | dsp->dtmf.lastwhat = what; | ||
299 | |||
300 | goto again; | ||
301 | } | ||
302 | |||
303 | |||
diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h new file mode 100644 index 000000000000..8a20af43308b --- /dev/null +++ b/drivers/isdn/mISDN/dsp_ecdis.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * SpanDSP - a series of DSP components for telephony | ||
3 | * | ||
4 | * ec_disable_detector.h - A detector which should eventually meet the | ||
5 | * G.164/G.165 requirements for detecting the | ||
6 | * 2100Hz echo cancellor disable tone. | ||
7 | * | ||
8 | * Written by Steve Underwood <steveu@coppice.org> | ||
9 | * | ||
10 | * Copyright (C) 2001 Steve Underwood | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include "dsp_biquad.h" | ||
31 | |||
32 | struct ec_disable_detector_state { | ||
33 | struct biquad2_state notch; | ||
34 | int notch_level; | ||
35 | int channel_level; | ||
36 | int tone_present; | ||
37 | int tone_cycle_duration; | ||
38 | int good_cycles; | ||
39 | int hit; | ||
40 | }; | ||
41 | |||
42 | |||
43 | #define FALSE 0 | ||
44 | #define TRUE (!FALSE) | ||
45 | |||
46 | static inline void | ||
47 | echo_can_disable_detector_init(struct ec_disable_detector_state *det) | ||
48 | { | ||
49 | /* Elliptic notch */ | ||
50 | /* This is actually centred at 2095Hz, but gets the balance we want, due | ||
51 | to the asymmetric walls of the notch */ | ||
52 | biquad2_init(&det->notch, | ||
53 | (int32_t) (-0.7600000*32768.0), | ||
54 | (int32_t) (-0.1183852*32768.0), | ||
55 | (int32_t) (-0.5104039*32768.0), | ||
56 | (int32_t) (0.1567596*32768.0), | ||
57 | (int32_t) (1.0000000*32768.0)); | ||
58 | |||
59 | det->channel_level = 0; | ||
60 | det->notch_level = 0; | ||
61 | det->tone_present = FALSE; | ||
62 | det->tone_cycle_duration = 0; | ||
63 | det->good_cycles = 0; | ||
64 | det->hit = 0; | ||
65 | } | ||
66 | /*- End of function --------------------------------------------------------*/ | ||
67 | |||
68 | static inline int | ||
69 | echo_can_disable_detector_update(struct ec_disable_detector_state *det, | ||
70 | int16_t amp) | ||
71 | { | ||
72 | int16_t notched; | ||
73 | |||
74 | notched = biquad2(&det->notch, amp); | ||
75 | /* Estimate the overall energy in the channel, and the energy in | ||
76 | the notch (i.e. overall channel energy - tone energy => noise). | ||
77 | Use abs instead of multiply for speed (is it really faster?). | ||
78 | Damp the overall energy a little more for a stable result. | ||
79 | Damp the notch energy a little less, so we don't damp out the | ||
80 | blip every time the phase reverses */ | ||
81 | det->channel_level += ((abs(amp) - det->channel_level) >> 5); | ||
82 | det->notch_level += ((abs(notched) - det->notch_level) >> 4); | ||
83 | if (det->channel_level > 280) { | ||
84 | /* There is adequate energy in the channel. | ||
85 | Is it mostly at 2100Hz? */ | ||
86 | if (det->notch_level*6 < det->channel_level) { | ||
87 | /* The notch says yes, so we have the tone. */ | ||
88 | if (!det->tone_present) { | ||
89 | /* Do we get a kick every 450+-25ms? */ | ||
90 | if (det->tone_cycle_duration >= 425*8 | ||
91 | && det->tone_cycle_duration <= 475*8) { | ||
92 | det->good_cycles++; | ||
93 | if (det->good_cycles > 2) | ||
94 | det->hit = TRUE; | ||
95 | } | ||
96 | det->tone_cycle_duration = 0; | ||
97 | } | ||
98 | det->tone_present = TRUE; | ||
99 | } else | ||
100 | det->tone_present = FALSE; | ||
101 | det->tone_cycle_duration++; | ||
102 | } else { | ||
103 | det->tone_present = FALSE; | ||
104 | det->tone_cycle_duration = 0; | ||
105 | det->good_cycles = 0; | ||
106 | } | ||
107 | return det->hit; | ||
108 | } | ||
109 | /*- End of function --------------------------------------------------------*/ | ||
110 | /*- End of file ------------------------------------------------------------*/ | ||
diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c new file mode 100644 index 000000000000..eb892d9dd5c6 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_hwec.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * dsp_hwec.c: | ||
3 | * builtin mISDN dsp pipeline element for enabling the hw echocanceller | ||
4 | * | ||
5 | * Copyright (C) 2007, Nadi Sarrar | ||
6 | * | ||
7 | * Nadi Sarrar <nadi@beronet.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the Free | ||
11 | * Software Foundation; either version 2 of the License, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
21 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called LICENSE. | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/mISDNdsp.h> | ||
31 | #include <linux/mISDNif.h> | ||
32 | #include "core.h" | ||
33 | #include "dsp.h" | ||
34 | #include "dsp_hwec.h" | ||
35 | |||
36 | static struct mISDN_dsp_element_arg args[] = { | ||
37 | { "deftaps", "128", "Set the number of taps of cancellation." }, | ||
38 | }; | ||
39 | |||
40 | static struct mISDN_dsp_element dsp_hwec_p = { | ||
41 | .name = "hwec", | ||
42 | .new = NULL, | ||
43 | .free = NULL, | ||
44 | .process_tx = NULL, | ||
45 | .process_rx = NULL, | ||
46 | .num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg), | ||
47 | .args = args, | ||
48 | }; | ||
49 | struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; | ||
50 | |||
51 | void dsp_hwec_enable(struct dsp *dsp, const char *arg) | ||
52 | { | ||
53 | int deftaps = 128, | ||
54 | len; | ||
55 | struct mISDN_ctrl_req cq; | ||
56 | |||
57 | if (!dsp) { | ||
58 | printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n", | ||
59 | __func__); | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | if (!arg) | ||
64 | goto _do; | ||
65 | |||
66 | len = strlen(arg); | ||
67 | if (!len) | ||
68 | goto _do; | ||
69 | |||
70 | { | ||
71 | char _dup[len + 1]; | ||
72 | char *dup, *tok, *name, *val; | ||
73 | int tmp; | ||
74 | |||
75 | strcpy(_dup, arg); | ||
76 | dup = _dup; | ||
77 | |||
78 | while ((tok = strsep(&dup, ","))) { | ||
79 | if (!strlen(tok)) | ||
80 | continue; | ||
81 | name = strsep(&tok, "="); | ||
82 | val = tok; | ||
83 | |||
84 | if (!val) | ||
85 | continue; | ||
86 | |||
87 | if (!strcmp(name, "deftaps")) { | ||
88 | if (sscanf(val, "%d", &tmp) == 1) | ||
89 | deftaps = tmp; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | _do: | ||
95 | printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n", | ||
96 | __func__, deftaps); | ||
97 | memset(&cq, 0, sizeof(cq)); | ||
98 | cq.op = MISDN_CTRL_HFC_ECHOCAN_ON; | ||
99 | cq.p1 = deftaps; | ||
100 | if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { | ||
101 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
102 | __func__); | ||
103 | return; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | void dsp_hwec_disable(struct dsp *dsp) | ||
108 | { | ||
109 | struct mISDN_ctrl_req cq; | ||
110 | |||
111 | if (!dsp) { | ||
112 | printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n", | ||
113 | __func__); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | printk(KERN_DEBUG "%s: disabling hwec\n", __func__); | ||
118 | memset(&cq, 0, sizeof(cq)); | ||
119 | cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF; | ||
120 | if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { | ||
121 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
122 | __func__); | ||
123 | return; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | int dsp_hwec_init(void) | ||
128 | { | ||
129 | mISDN_dsp_element_register(dsp_hwec); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | void dsp_hwec_exit(void) | ||
135 | { | ||
136 | mISDN_dsp_element_unregister(dsp_hwec); | ||
137 | } | ||
138 | |||
diff --git a/drivers/isdn/mISDN/dsp_hwec.h b/drivers/isdn/mISDN/dsp_hwec.h new file mode 100644 index 000000000000..eebe80c3f713 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_hwec.h | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * dsp_hwec.h | ||
3 | */ | ||
4 | |||
5 | extern struct mISDN_dsp_element *dsp_hwec; | ||
6 | extern void dsp_hwec_enable(struct dsp *dsp, const char *arg); | ||
7 | extern void dsp_hwec_disable(struct dsp *dsp); | ||
8 | extern int dsp_hwec_init(void); | ||
9 | extern void dsp_hwec_exit(void); | ||
10 | |||
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c new file mode 100644 index 000000000000..850260ab57d0 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_pipeline.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * dsp_pipeline.c: pipelined audio processing | ||
3 | * | ||
4 | * Copyright (C) 2007, Nadi Sarrar | ||
5 | * | ||
6 | * Nadi Sarrar <nadi@beronet.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the Free | ||
10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
20 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | * | ||
22 | * The full GNU General Public License is included in this distribution in the | ||
23 | * file called LICENSE. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/mISDNif.h> | ||
31 | #include <linux/mISDNdsp.h> | ||
32 | #include "dsp.h" | ||
33 | #include "dsp_hwec.h" | ||
34 | |||
35 | /* uncomment for debugging */ | ||
36 | /*#define PIPELINE_DEBUG*/ | ||
37 | |||
38 | struct dsp_pipeline_entry { | ||
39 | struct mISDN_dsp_element *elem; | ||
40 | void *p; | ||
41 | struct list_head list; | ||
42 | }; | ||
43 | struct dsp_element_entry { | ||
44 | struct mISDN_dsp_element *elem; | ||
45 | struct device dev; | ||
46 | struct list_head list; | ||
47 | }; | ||
48 | |||
49 | static LIST_HEAD(dsp_elements); | ||
50 | |||
51 | /* sysfs */ | ||
52 | static struct class *elements_class; | ||
53 | |||
54 | static ssize_t | ||
55 | attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) | ||
56 | { | ||
57 | struct mISDN_dsp_element *elem = dev_get_drvdata(dev); | ||
58 | ssize_t len = 0; | ||
59 | int i = 0; | ||
60 | |||
61 | *buf = 0; | ||
62 | for (; i < elem->num_args; ++i) | ||
63 | len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" | ||
64 | "\n", buf, | ||
65 | elem->args[i].name, | ||
66 | elem->args[i].def ? "Default: " : "", | ||
67 | elem->args[i].def ? elem->args[i].def : "", | ||
68 | elem->args[i].def ? "\n" : "", | ||
69 | elem->args[i].desc); | ||
70 | |||
71 | return len; | ||
72 | } | ||
73 | |||
74 | static struct device_attribute element_attributes[] = { | ||
75 | __ATTR(args, 0444, attr_show_args, NULL), | ||
76 | }; | ||
77 | |||
78 | int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) | ||
79 | { | ||
80 | struct dsp_element_entry *entry; | ||
81 | int ret, i; | ||
82 | |||
83 | if (!elem) | ||
84 | return -EINVAL; | ||
85 | |||
86 | entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL); | ||
87 | if (!entry) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | entry->elem = elem; | ||
91 | |||
92 | entry->dev.class = elements_class; | ||
93 | dev_set_drvdata(&entry->dev, elem); | ||
94 | snprintf(entry->dev.bus_id, BUS_ID_SIZE, elem->name); | ||
95 | ret = device_register(&entry->dev); | ||
96 | if (ret) { | ||
97 | printk(KERN_ERR "%s: failed to register %s\n", | ||
98 | __func__, elem->name); | ||
99 | goto err1; | ||
100 | } | ||
101 | |||
102 | for (i = 0; i < (sizeof(element_attributes) | ||
103 | / sizeof(struct device_attribute)); ++i) | ||
104 | ret = device_create_file(&entry->dev, | ||
105 | &element_attributes[i]); | ||
106 | if (ret) { | ||
107 | printk(KERN_ERR "%s: failed to create device file\n", | ||
108 | __func__); | ||
109 | goto err2; | ||
110 | } | ||
111 | |||
112 | list_add_tail(&entry->list, &dsp_elements); | ||
113 | |||
114 | printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name); | ||
115 | |||
116 | return 0; | ||
117 | |||
118 | err2: | ||
119 | device_unregister(&entry->dev); | ||
120 | err1: | ||
121 | kfree(entry); | ||
122 | return ret; | ||
123 | } | ||
124 | EXPORT_SYMBOL(mISDN_dsp_element_register); | ||
125 | |||
126 | void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem) | ||
127 | { | ||
128 | struct dsp_element_entry *entry, *n; | ||
129 | |||
130 | if (!elem) | ||
131 | return; | ||
132 | |||
133 | list_for_each_entry_safe(entry, n, &dsp_elements, list) | ||
134 | if (entry->elem == elem) { | ||
135 | list_del(&entry->list); | ||
136 | device_unregister(&entry->dev); | ||
137 | kfree(entry); | ||
138 | printk(KERN_DEBUG "%s: %s unregistered\n", | ||
139 | __func__, elem->name); | ||
140 | return; | ||
141 | } | ||
142 | printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); | ||
143 | } | ||
144 | EXPORT_SYMBOL(mISDN_dsp_element_unregister); | ||
145 | |||
146 | int dsp_pipeline_module_init(void) | ||
147 | { | ||
148 | elements_class = class_create(THIS_MODULE, "dsp_pipeline"); | ||
149 | if (IS_ERR(elements_class)) | ||
150 | return PTR_ERR(elements_class); | ||
151 | |||
152 | #ifdef PIPELINE_DEBUG | ||
153 | printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__); | ||
154 | #endif | ||
155 | |||
156 | dsp_hwec_init(); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | void dsp_pipeline_module_exit(void) | ||
162 | { | ||
163 | struct dsp_element_entry *entry, *n; | ||
164 | |||
165 | dsp_hwec_exit(); | ||
166 | |||
167 | class_destroy(elements_class); | ||
168 | |||
169 | list_for_each_entry_safe(entry, n, &dsp_elements, list) { | ||
170 | list_del(&entry->list); | ||
171 | printk(KERN_WARNING "%s: element was still registered: %s\n", | ||
172 | __func__, entry->elem->name); | ||
173 | kfree(entry); | ||
174 | } | ||
175 | |||
176 | printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__); | ||
177 | } | ||
178 | |||
179 | int dsp_pipeline_init(struct dsp_pipeline *pipeline) | ||
180 | { | ||
181 | if (!pipeline) | ||
182 | return -EINVAL; | ||
183 | |||
184 | INIT_LIST_HEAD(&pipeline->list); | ||
185 | |||
186 | #ifdef PIPELINE_DEBUG | ||
187 | printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__); | ||
188 | #endif | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline) | ||
194 | { | ||
195 | struct dsp_pipeline_entry *entry, *n; | ||
196 | |||
197 | list_for_each_entry_safe(entry, n, &pipeline->list, list) { | ||
198 | list_del(&entry->list); | ||
199 | if (entry->elem == dsp_hwec) | ||
200 | dsp_hwec_disable(container_of(pipeline, struct dsp, | ||
201 | pipeline)); | ||
202 | else | ||
203 | entry->elem->free(entry->p); | ||
204 | kfree(entry); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | void dsp_pipeline_destroy(struct dsp_pipeline *pipeline) | ||
209 | { | ||
210 | |||
211 | if (!pipeline) | ||
212 | return; | ||
213 | |||
214 | _dsp_pipeline_destroy(pipeline); | ||
215 | |||
216 | #ifdef PIPELINE_DEBUG | ||
217 | printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__); | ||
218 | #endif | ||
219 | } | ||
220 | |||
221 | int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) | ||
222 | { | ||
223 | int len, incomplete = 0, found = 0; | ||
224 | char *dup, *tok, *name, *args; | ||
225 | struct dsp_element_entry *entry, *n; | ||
226 | struct dsp_pipeline_entry *pipeline_entry; | ||
227 | struct mISDN_dsp_element *elem; | ||
228 | |||
229 | if (!pipeline) | ||
230 | return -EINVAL; | ||
231 | |||
232 | if (!list_empty(&pipeline->list)) | ||
233 | _dsp_pipeline_destroy(pipeline); | ||
234 | |||
235 | if (!cfg) | ||
236 | return 0; | ||
237 | |||
238 | len = strlen(cfg); | ||
239 | if (!len) | ||
240 | return 0; | ||
241 | |||
242 | dup = kmalloc(len + 1, GFP_KERNEL); | ||
243 | if (!dup) | ||
244 | return 0; | ||
245 | strcpy(dup, cfg); | ||
246 | while ((tok = strsep(&dup, "|"))) { | ||
247 | if (!strlen(tok)) | ||
248 | continue; | ||
249 | name = strsep(&tok, "("); | ||
250 | args = strsep(&tok, ")"); | ||
251 | if (args && !*args) | ||
252 | args = 0; | ||
253 | |||
254 | list_for_each_entry_safe(entry, n, &dsp_elements, list) | ||
255 | if (!strcmp(entry->elem->name, name)) { | ||
256 | elem = entry->elem; | ||
257 | |||
258 | pipeline_entry = kmalloc(sizeof(struct | ||
259 | dsp_pipeline_entry), GFP_KERNEL); | ||
260 | if (!pipeline_entry) { | ||
261 | printk(KERN_DEBUG "%s: failed to add " | ||
262 | "entry to pipeline: %s (out of " | ||
263 | "memory)\n", __func__, elem->name); | ||
264 | incomplete = 1; | ||
265 | goto _out; | ||
266 | } | ||
267 | pipeline_entry->elem = elem; | ||
268 | |||
269 | if (elem == dsp_hwec) { | ||
270 | /* This is a hack to make the hwec | ||
271 | available as a pipeline module */ | ||
272 | dsp_hwec_enable(container_of(pipeline, | ||
273 | struct dsp, pipeline), args); | ||
274 | list_add_tail(&pipeline_entry->list, | ||
275 | &pipeline->list); | ||
276 | } else { | ||
277 | pipeline_entry->p = elem->new(args); | ||
278 | if (pipeline_entry->p) { | ||
279 | list_add_tail(&pipeline_entry-> | ||
280 | list, &pipeline->list); | ||
281 | #ifdef PIPELINE_DEBUG | ||
282 | printk(KERN_DEBUG "%s: created " | ||
283 | "instance of %s%s%s\n", | ||
284 | __func__, name, args ? | ||
285 | " with args " : "", args ? | ||
286 | args : ""); | ||
287 | #endif | ||
288 | } else { | ||
289 | printk(KERN_DEBUG "%s: failed " | ||
290 | "to add entry to pipeline: " | ||
291 | "%s (new() returned NULL)\n", | ||
292 | __func__, elem->name); | ||
293 | kfree(pipeline_entry); | ||
294 | incomplete = 1; | ||
295 | } | ||
296 | } | ||
297 | found = 1; | ||
298 | break; | ||
299 | } | ||
300 | |||
301 | if (found) | ||
302 | found = 0; | ||
303 | else { | ||
304 | printk(KERN_DEBUG "%s: element not found, skipping: " | ||
305 | "%s\n", __func__, name); | ||
306 | incomplete = 1; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | _out: | ||
311 | if (!list_empty(&pipeline->list)) | ||
312 | pipeline->inuse = 1; | ||
313 | else | ||
314 | pipeline->inuse = 0; | ||
315 | |||
316 | #ifdef PIPELINE_DEBUG | ||
317 | printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n", | ||
318 | __func__, incomplete ? " incomplete" : "", cfg); | ||
319 | #endif | ||
320 | kfree(dup); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) | ||
325 | { | ||
326 | struct dsp_pipeline_entry *entry; | ||
327 | |||
328 | if (!pipeline) | ||
329 | return; | ||
330 | |||
331 | list_for_each_entry(entry, &pipeline->list, list) | ||
332 | if (entry->elem->process_tx) | ||
333 | entry->elem->process_tx(entry->p, data, len); | ||
334 | } | ||
335 | |||
336 | void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) | ||
337 | { | ||
338 | struct dsp_pipeline_entry *entry; | ||
339 | |||
340 | if (!pipeline) | ||
341 | return; | ||
342 | |||
343 | list_for_each_entry_reverse(entry, &pipeline->list, list) | ||
344 | if (entry->elem->process_rx) | ||
345 | entry->elem->process_rx(entry->p, data, len); | ||
346 | } | ||
347 | |||
348 | |||
diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c new file mode 100644 index 000000000000..23dd0dd21524 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_tones.c | |||
@@ -0,0 +1,551 @@ | |||
1 | /* | ||
2 | * Audio support data for ISDN4Linux. | ||
3 | * | ||
4 | * Copyright Andreas Eversberg (jolly@eversberg.eu) | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms | ||
7 | * of the GNU General Public License, incorporated herein by reference. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/mISDNif.h> | ||
12 | #include <linux/mISDNdsp.h> | ||
13 | #include "core.h" | ||
14 | #include "dsp.h" | ||
15 | |||
16 | |||
17 | #define DATA_S sample_silence | ||
18 | #define SIZE_S (&sizeof_silence) | ||
19 | #define DATA_GA sample_german_all | ||
20 | #define SIZE_GA (&sizeof_german_all) | ||
21 | #define DATA_GO sample_german_old | ||
22 | #define SIZE_GO (&sizeof_german_old) | ||
23 | #define DATA_DT sample_american_dialtone | ||
24 | #define SIZE_DT (&sizeof_american_dialtone) | ||
25 | #define DATA_RI sample_american_ringing | ||
26 | #define SIZE_RI (&sizeof_american_ringing) | ||
27 | #define DATA_BU sample_american_busy | ||
28 | #define SIZE_BU (&sizeof_american_busy) | ||
29 | #define DATA_S1 sample_special1 | ||
30 | #define SIZE_S1 (&sizeof_special1) | ||
31 | #define DATA_S2 sample_special2 | ||
32 | #define SIZE_S2 (&sizeof_special2) | ||
33 | #define DATA_S3 sample_special3 | ||
34 | #define SIZE_S3 (&sizeof_special3) | ||
35 | |||
36 | /***************/ | ||
37 | /* tones loops */ | ||
38 | /***************/ | ||
39 | |||
40 | /* all tones are alaw encoded */ | ||
41 | /* the last sample+1 is in phase with the first sample. the error is low */ | ||
42 | |||
43 | static u8 sample_german_all[] = { | ||
44 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
45 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
46 | 0xdc, 0xfc, 0x6c, | ||
47 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
48 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
49 | 0xdc, 0xfc, 0x6c, | ||
50 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
51 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
52 | 0xdc, 0xfc, 0x6c, | ||
53 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
54 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
55 | 0xdc, 0xfc, 0x6c, | ||
56 | }; | ||
57 | static u32 sizeof_german_all = sizeof(sample_german_all); | ||
58 | |||
59 | static u8 sample_german_old[] = { | ||
60 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
61 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
62 | 0x8c, | ||
63 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
64 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
65 | 0x8c, | ||
66 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
67 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
68 | 0x8c, | ||
69 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
70 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
71 | 0x8c, | ||
72 | }; | ||
73 | static u32 sizeof_german_old = sizeof(sample_german_old); | ||
74 | |||
75 | static u8 sample_american_dialtone[] = { | ||
76 | 0x2a, 0x18, 0x90, 0x6c, 0x4c, 0xbc, 0x4c, 0x6c, | ||
77 | 0x10, 0x58, 0x32, 0xb9, 0x31, 0x2d, 0x8d, 0x0d, | ||
78 | 0x8d, 0x2d, 0x31, 0x99, 0x0f, 0x28, 0x60, 0xf0, | ||
79 | 0xd0, 0x50, 0xd0, 0x30, 0x60, 0x08, 0x8e, 0x67, | ||
80 | 0x09, 0x19, 0x21, 0xe1, 0xd9, 0xb9, 0x29, 0x67, | ||
81 | 0x83, 0x02, 0xce, 0xbe, 0xee, 0x1a, 0x1b, 0xef, | ||
82 | 0xbf, 0xcf, 0x03, 0x82, 0x66, 0x28, 0xb8, 0xd8, | ||
83 | 0xe0, 0x20, 0x18, 0x08, 0x66, 0x8f, 0x09, 0x61, | ||
84 | 0x31, 0xd1, 0x51, 0xd1, 0xf1, 0x61, 0x29, 0x0e, | ||
85 | 0x98, 0x30, 0x2c, 0x8c, 0x0c, 0x8c, 0x2c, 0x30, | ||
86 | 0xb8, 0x33, 0x59, 0x11, 0x6d, 0x4d, 0xbd, 0x4d, | ||
87 | 0x6d, 0x91, 0x19, | ||
88 | }; | ||
89 | static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone); | ||
90 | |||
91 | static u8 sample_american_ringing[] = { | ||
92 | 0x2a, 0xe0, 0xac, 0x0c, 0xbc, 0x4c, 0x8c, 0x90, | ||
93 | 0x48, 0xc7, 0xc1, 0xed, 0xcd, 0x4d, 0xcd, 0xed, | ||
94 | 0xc1, 0xb7, 0x08, 0x30, 0xec, 0xcc, 0xcc, 0x8c, | ||
95 | 0x10, 0x58, 0x1a, 0x99, 0x71, 0xed, 0x8d, 0x8d, | ||
96 | 0x2d, 0x41, 0x89, 0x9e, 0x20, 0x70, 0x2c, 0xec, | ||
97 | 0x2c, 0x70, 0x20, 0x86, 0x77, 0xe1, 0x31, 0x11, | ||
98 | 0xd1, 0xf1, 0x81, 0x09, 0xa3, 0x56, 0x58, 0x00, | ||
99 | 0x40, 0xc0, 0x60, 0x38, 0x46, 0x43, 0x57, 0x39, | ||
100 | 0xd9, 0x59, 0x99, 0xc9, 0x77, 0x2f, 0x2e, 0xc6, | ||
101 | 0xd6, 0x28, 0xd6, 0x36, 0x26, 0x2e, 0x8a, 0xa3, | ||
102 | 0x43, 0x63, 0x4b, 0x4a, 0x62, 0x42, 0xa2, 0x8b, | ||
103 | 0x2f, 0x27, 0x37, 0xd7, 0x29, 0xd7, 0xc7, 0x2f, | ||
104 | 0x2e, 0x76, 0xc8, 0x98, 0x58, 0xd8, 0x38, 0x56, | ||
105 | 0x42, 0x47, 0x39, 0x61, 0xc1, 0x41, 0x01, 0x59, | ||
106 | 0x57, 0xa2, 0x08, 0x80, 0xf0, 0xd0, 0x10, 0x30, | ||
107 | 0xe0, 0x76, 0x87, 0x21, 0x71, 0x2d, 0xed, 0x2d, | ||
108 | 0x71, 0x21, 0x9f, 0x88, 0x40, 0x2c, 0x8c, 0x8c, | ||
109 | 0xec, 0x70, 0x98, 0x1b, 0x59, 0x11, 0x8d, 0xcd, | ||
110 | 0xcd, 0xed, 0x31, 0x09, 0xb6, 0xc0, 0xec, 0xcc, | ||
111 | 0x4c, 0xcc, 0xec, 0xc0, 0xc6, 0x49, 0x91, 0x8d, | ||
112 | 0x4d, 0xbd, 0x0d, 0xad, 0xe1, | ||
113 | }; | ||
114 | static u32 sizeof_american_ringing = sizeof(sample_american_ringing); | ||
115 | |||
116 | static u8 sample_american_busy[] = { | ||
117 | 0x2a, 0x00, 0x6c, 0x4c, 0x4c, 0x6c, 0xb0, 0x66, | ||
118 | 0x99, 0x11, 0x6d, 0x8d, 0x2d, 0x41, 0xd7, 0x96, | ||
119 | 0x60, 0xf0, 0x70, 0x40, 0x58, 0xf6, 0x53, 0x57, | ||
120 | 0x09, 0x89, 0xd7, 0x5f, 0xe3, 0x2a, 0xe3, 0x5f, | ||
121 | 0xd7, 0x89, 0x09, 0x57, 0x53, 0xf6, 0x58, 0x40, | ||
122 | 0x70, 0xf0, 0x60, 0x96, 0xd7, 0x41, 0x2d, 0x8d, | ||
123 | 0x6d, 0x11, 0x99, 0x66, 0xb0, 0x6c, 0x4c, 0x4c, | ||
124 | 0x6c, 0x00, 0x2a, 0x01, 0x6d, 0x4d, 0x4d, 0x6d, | ||
125 | 0xb1, 0x67, 0x98, 0x10, 0x6c, 0x8c, 0x2c, 0x40, | ||
126 | 0xd6, 0x97, 0x61, 0xf1, 0x71, 0x41, 0x59, 0xf7, | ||
127 | 0x52, 0x56, 0x08, 0x88, 0xd6, 0x5e, 0xe2, 0x2a, | ||
128 | 0xe2, 0x5e, 0xd6, 0x88, 0x08, 0x56, 0x52, 0xf7, | ||
129 | 0x59, 0x41, 0x71, 0xf1, 0x61, 0x97, 0xd6, 0x40, | ||
130 | 0x2c, 0x8c, 0x6c, 0x10, 0x98, 0x67, 0xb1, 0x6d, | ||
131 | 0x4d, 0x4d, 0x6d, 0x01, | ||
132 | }; | ||
133 | static u32 sizeof_american_busy = sizeof(sample_american_busy); | ||
134 | |||
135 | static u8 sample_special1[] = { | ||
136 | 0x2a, 0x2c, 0xbc, 0x6c, 0xd6, 0x71, 0xbd, 0x0d, | ||
137 | 0xd9, 0x80, 0xcc, 0x4c, 0x40, 0x39, 0x0d, 0xbd, | ||
138 | 0x11, 0x86, 0xec, 0xbc, 0xec, 0x0e, 0x51, 0xbd, | ||
139 | 0x8d, 0x89, 0x30, 0x4c, 0xcc, 0xe0, 0xe1, 0xcd, | ||
140 | 0x4d, 0x31, 0x88, 0x8c, 0xbc, 0x50, 0x0f, 0xed, | ||
141 | 0xbd, 0xed, 0x87, 0x10, 0xbc, 0x0c, 0x38, 0x41, | ||
142 | 0x4d, 0xcd, 0x81, 0xd8, 0x0c, 0xbc, 0x70, 0xd7, | ||
143 | 0x6d, 0xbd, 0x2d, | ||
144 | }; | ||
145 | static u32 sizeof_special1 = sizeof(sample_special1); | ||
146 | |||
147 | static u8 sample_special2[] = { | ||
148 | 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, | ||
149 | 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, | ||
150 | 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, | ||
151 | 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, | ||
152 | 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, | ||
153 | 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, | ||
154 | 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, | ||
155 | 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, | ||
156 | 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, | ||
157 | 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, | ||
158 | }; | ||
159 | static u32 sizeof_special2 = sizeof(sample_special2); | ||
160 | |||
161 | static u8 sample_special3[] = { | ||
162 | 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, | ||
163 | 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, | ||
164 | 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, | ||
165 | 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, | ||
166 | 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, | ||
167 | 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, | ||
168 | 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, | ||
169 | 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, | ||
170 | 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, | ||
171 | 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, | ||
172 | }; | ||
173 | static u32 sizeof_special3 = sizeof(sample_special3); | ||
174 | |||
175 | static u8 sample_silence[] = { | ||
176 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
177 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
178 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
179 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
180 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
181 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
182 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
183 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
184 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
185 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
186 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
187 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
188 | }; | ||
189 | static u32 sizeof_silence = sizeof(sample_silence); | ||
190 | |||
191 | struct tones_samples { | ||
192 | u32 *len; | ||
193 | u8 *data; | ||
194 | }; | ||
195 | static struct | ||
196 | tones_samples samples[] = { | ||
197 | {&sizeof_german_all, sample_german_all}, | ||
198 | {&sizeof_german_old, sample_german_old}, | ||
199 | {&sizeof_american_dialtone, sample_american_dialtone}, | ||
200 | {&sizeof_american_ringing, sample_american_ringing}, | ||
201 | {&sizeof_american_busy, sample_american_busy}, | ||
202 | {&sizeof_special1, sample_special1}, | ||
203 | {&sizeof_special2, sample_special2}, | ||
204 | {&sizeof_special3, sample_special3}, | ||
205 | {NULL, NULL}, | ||
206 | }; | ||
207 | |||
208 | /*********************************** | ||
209 | * generate ulaw from alaw samples * | ||
210 | ***********************************/ | ||
211 | |||
212 | void | ||
213 | dsp_audio_generate_ulaw_samples(void) | ||
214 | { | ||
215 | int i, j; | ||
216 | |||
217 | i = 0; | ||
218 | while (samples[i].len) { | ||
219 | j = 0; | ||
220 | while (j < (*samples[i].len)) { | ||
221 | samples[i].data[j] = | ||
222 | dsp_audio_alaw_to_ulaw[samples[i].data[j]]; | ||
223 | j++; | ||
224 | } | ||
225 | i++; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | |||
230 | /**************************** | ||
231 | * tone sequence definition * | ||
232 | ****************************/ | ||
233 | |||
234 | struct pattern { | ||
235 | int tone; | ||
236 | u8 *data[10]; | ||
237 | u32 *siz[10]; | ||
238 | u32 seq[10]; | ||
239 | } pattern[] = { | ||
240 | {TONE_GERMAN_DIALTONE, | ||
241 | {DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
242 | {SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
243 | {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
244 | |||
245 | {TONE_GERMAN_OLDDIALTONE, | ||
246 | {DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
247 | {SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
248 | {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
249 | |||
250 | {TONE_AMERICAN_DIALTONE, | ||
251 | {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
252 | {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
253 | {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
254 | |||
255 | {TONE_GERMAN_DIALPBX, | ||
256 | {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0}, | ||
257 | {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0}, | ||
258 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
259 | |||
260 | {TONE_GERMAN_OLDDIALPBX, | ||
261 | {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0}, | ||
262 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0}, | ||
263 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
264 | |||
265 | {TONE_AMERICAN_DIALPBX, | ||
266 | {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0}, | ||
267 | {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0}, | ||
268 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
269 | |||
270 | {TONE_GERMAN_RINGING, | ||
271 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
272 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
273 | {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
274 | |||
275 | {TONE_GERMAN_OLDRINGING, | ||
276 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
277 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
278 | {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
279 | |||
280 | {TONE_AMERICAN_RINGING, | ||
281 | {DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
282 | {SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
283 | {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
284 | |||
285 | {TONE_GERMAN_RINGPBX, | ||
286 | {DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
287 | {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
288 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
289 | |||
290 | {TONE_GERMAN_OLDRINGPBX, | ||
291 | {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
292 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
293 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
294 | |||
295 | {TONE_AMERICAN_RINGPBX, | ||
296 | {DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
297 | {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
298 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
299 | |||
300 | {TONE_GERMAN_BUSY, | ||
301 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
302 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
303 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
304 | |||
305 | {TONE_GERMAN_OLDBUSY, | ||
306 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
307 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
308 | {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
309 | |||
310 | {TONE_AMERICAN_BUSY, | ||
311 | {DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
312 | {SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
313 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
314 | |||
315 | {TONE_GERMAN_HANGUP, | ||
316 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
317 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
318 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
319 | |||
320 | {TONE_GERMAN_OLDHANGUP, | ||
321 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
322 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
323 | {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
324 | |||
325 | {TONE_AMERICAN_HANGUP, | ||
326 | {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
327 | {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
328 | {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
329 | |||
330 | {TONE_SPECIAL_INFO, | ||
331 | {DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
332 | {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
333 | {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, | ||
334 | |||
335 | {TONE_GERMAN_GASSENBESETZT, | ||
336 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
337 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
338 | {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
339 | |||
340 | {TONE_GERMAN_AUFSCHALTTON, | ||
341 | {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
342 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
343 | {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, | ||
344 | |||
345 | {0, | ||
346 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
347 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
348 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
349 | }; | ||
350 | |||
351 | /****************** | ||
352 | * copy tone data * | ||
353 | ******************/ | ||
354 | |||
355 | /* an sk_buff is generated from the number of samples needed. | ||
356 | * the count will be changed and may begin from 0 each pattern period. | ||
357 | * the clue is to precalculate the pointers and legths to use only one | ||
358 | * memcpy per function call, or two memcpy if the tone sequence changes. | ||
359 | * | ||
360 | * pattern - the type of the pattern | ||
361 | * count - the sample from the beginning of the pattern (phase) | ||
362 | * len - the number of bytes | ||
363 | * | ||
364 | * return - the sk_buff with the sample | ||
365 | * | ||
366 | * if tones has finished (e.g. knocking tone), dsp->tones is turned off | ||
367 | */ | ||
368 | void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) | ||
369 | { | ||
370 | int index, count, start, num; | ||
371 | struct pattern *pat; | ||
372 | struct dsp_tone *tone = &dsp->tone; | ||
373 | |||
374 | /* if we have no tone, we copy silence */ | ||
375 | if (!tone->tone) { | ||
376 | memset(data, dsp_silence, len); | ||
377 | return; | ||
378 | } | ||
379 | |||
380 | /* process pattern */ | ||
381 | pat = (struct pattern *)tone->pattern; | ||
382 | /* points to the current pattern */ | ||
383 | index = tone->index; /* gives current sequence index */ | ||
384 | count = tone->count; /* gives current sample */ | ||
385 | |||
386 | /* copy sample */ | ||
387 | while (len) { | ||
388 | /* find sample to start with */ | ||
389 | while (42) { | ||
390 | /* warp arround */ | ||
391 | if (!pat->seq[index]) { | ||
392 | count = 0; | ||
393 | index = 0; | ||
394 | } | ||
395 | /* check if we are currently playing this tone */ | ||
396 | if (count < pat->seq[index]) | ||
397 | break; | ||
398 | if (dsp_debug & DEBUG_DSP_TONE) | ||
399 | printk(KERN_DEBUG "%s: reaching next sequence " | ||
400 | "(index=%d)\n", __func__, index); | ||
401 | count -= pat->seq[index]; | ||
402 | index++; | ||
403 | } | ||
404 | /* calculate start and number of samples */ | ||
405 | start = count % (*(pat->siz[index])); | ||
406 | num = len; | ||
407 | if (num+count > pat->seq[index]) | ||
408 | num = pat->seq[index] - count; | ||
409 | if (num+start > (*(pat->siz[index]))) | ||
410 | num = (*(pat->siz[index])) - start; | ||
411 | /* copy memory */ | ||
412 | memcpy(data, pat->data[index]+start, num); | ||
413 | /* reduce length */ | ||
414 | data += num; | ||
415 | count += num; | ||
416 | len -= num; | ||
417 | } | ||
418 | tone->index = index; | ||
419 | tone->count = count; | ||
420 | |||
421 | /* return sk_buff */ | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | |||
426 | /******************************* | ||
427 | * send HW message to hfc card * | ||
428 | *******************************/ | ||
429 | |||
430 | static void | ||
431 | dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) | ||
432 | { | ||
433 | struct sk_buff *nskb; | ||
434 | |||
435 | /* unlocking is not required, because we don't expect a response */ | ||
436 | nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, | ||
437 | (len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample, | ||
438 | GFP_ATOMIC); | ||
439 | if (nskb) { | ||
440 | if (dsp->ch.peer) { | ||
441 | if (dsp->ch.recv(dsp->ch.peer, nskb)) | ||
442 | dev_kfree_skb(nskb); | ||
443 | } else | ||
444 | dev_kfree_skb(nskb); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | |||
449 | /***************** | ||
450 | * timer expires * | ||
451 | *****************/ | ||
452 | void | ||
453 | dsp_tone_timeout(void *arg) | ||
454 | { | ||
455 | struct dsp *dsp = arg; | ||
456 | struct dsp_tone *tone = &dsp->tone; | ||
457 | struct pattern *pat = (struct pattern *)tone->pattern; | ||
458 | int index = tone->index; | ||
459 | |||
460 | if (!tone->tone) | ||
461 | return; | ||
462 | |||
463 | index++; | ||
464 | if (!pat->seq[index]) | ||
465 | index = 0; | ||
466 | tone->index = index; | ||
467 | |||
468 | /* set next tone */ | ||
469 | if (pat->data[index] == DATA_S) | ||
470 | dsp_tone_hw_message(dsp, 0, 0); | ||
471 | else | ||
472 | dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); | ||
473 | /* set timer */ | ||
474 | init_timer(&tone->tl); | ||
475 | tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000; | ||
476 | add_timer(&tone->tl); | ||
477 | } | ||
478 | |||
479 | |||
480 | /******************** | ||
481 | * set/release tone * | ||
482 | ********************/ | ||
483 | |||
484 | /* | ||
485 | * tones are relaized by streaming or by special loop commands if supported | ||
486 | * by hardware. when hardware is used, the patterns will be controlled by | ||
487 | * timers. | ||
488 | */ | ||
489 | int | ||
490 | dsp_tone(struct dsp *dsp, int tone) | ||
491 | { | ||
492 | struct pattern *pat; | ||
493 | int i; | ||
494 | struct dsp_tone *tonet = &dsp->tone; | ||
495 | |||
496 | tonet->software = 0; | ||
497 | tonet->hardware = 0; | ||
498 | |||
499 | /* we turn off the tone */ | ||
500 | if (!tone) { | ||
501 | if (dsp->features.hfc_loops) | ||
502 | if (timer_pending(&tonet->tl)) | ||
503 | del_timer(&tonet->tl); | ||
504 | if (dsp->features.hfc_loops) | ||
505 | dsp_tone_hw_message(dsp, NULL, 0); | ||
506 | tonet->tone = 0; | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | pat = NULL; | ||
511 | i = 0; | ||
512 | while (pattern[i].tone) { | ||
513 | if (pattern[i].tone == tone) { | ||
514 | pat = &pattern[i]; | ||
515 | break; | ||
516 | } | ||
517 | i++; | ||
518 | } | ||
519 | if (!pat) { | ||
520 | printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone); | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | if (dsp_debug & DEBUG_DSP_TONE) | ||
524 | printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", | ||
525 | __func__, tone, 0); | ||
526 | tonet->tone = tone; | ||
527 | tonet->pattern = pat; | ||
528 | tonet->index = 0; | ||
529 | tonet->count = 0; | ||
530 | |||
531 | if (dsp->features.hfc_loops) { | ||
532 | tonet->hardware = 1; | ||
533 | /* set first tone */ | ||
534 | dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0])); | ||
535 | /* set timer */ | ||
536 | if (timer_pending(&tonet->tl)) | ||
537 | del_timer(&tonet->tl); | ||
538 | init_timer(&tonet->tl); | ||
539 | tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000; | ||
540 | add_timer(&tonet->tl); | ||
541 | } else { | ||
542 | tonet->software = 1; | ||
543 | } | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | |||
549 | |||
550 | |||
551 | |||
diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c new file mode 100644 index 000000000000..b5d6553f2dc8 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * finite state machine implementation | ||
3 | * | ||
4 | * Author Karsten Keil <kkeil@novell.com> | ||
5 | * | ||
6 | * Thanks to Jan den Ouden | ||
7 | * Fritz Elfert | ||
8 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
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 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/string.h> | ||
25 | #include "fsm.h" | ||
26 | |||
27 | #define FSM_TIMER_DEBUG 0 | ||
28 | |||
29 | void | ||
30 | mISDN_FsmNew(struct Fsm *fsm, | ||
31 | struct FsmNode *fnlist, int fncount) | ||
32 | { | ||
33 | int i; | ||
34 | |||
35 | fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * | ||
36 | fsm->event_count, GFP_KERNEL); | ||
37 | |||
38 | for (i = 0; i < fncount; i++) | ||
39 | if ((fnlist[i].state >= fsm->state_count) || | ||
40 | (fnlist[i].event >= fsm->event_count)) { | ||
41 | printk(KERN_ERR | ||
42 | "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", | ||
43 | i, (long)fnlist[i].state, (long)fsm->state_count, | ||
44 | (long)fnlist[i].event, (long)fsm->event_count); | ||
45 | } else | ||
46 | fsm->jumpmatrix[fsm->state_count * fnlist[i].event + | ||
47 | fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; | ||
48 | } | ||
49 | EXPORT_SYMBOL(mISDN_FsmNew); | ||
50 | |||
51 | void | ||
52 | mISDN_FsmFree(struct Fsm *fsm) | ||
53 | { | ||
54 | kfree((void *) fsm->jumpmatrix); | ||
55 | } | ||
56 | EXPORT_SYMBOL(mISDN_FsmFree); | ||
57 | |||
58 | int | ||
59 | mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg) | ||
60 | { | ||
61 | FSMFNPTR r; | ||
62 | |||
63 | if ((fi->state >= fi->fsm->state_count) || | ||
64 | (event >= fi->fsm->event_count)) { | ||
65 | printk(KERN_ERR | ||
66 | "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", | ||
67 | (long)fi->state, (long)fi->fsm->state_count, event, | ||
68 | (long)fi->fsm->event_count); | ||
69 | return 1; | ||
70 | } | ||
71 | r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; | ||
72 | if (r) { | ||
73 | if (fi->debug) | ||
74 | fi->printdebug(fi, "State %s Event %s", | ||
75 | fi->fsm->strState[fi->state], | ||
76 | fi->fsm->strEvent[event]); | ||
77 | r(fi, event, arg); | ||
78 | return 0; | ||
79 | } else { | ||
80 | if (fi->debug) | ||
81 | fi->printdebug(fi, "State %s Event %s no action", | ||
82 | fi->fsm->strState[fi->state], | ||
83 | fi->fsm->strEvent[event]); | ||
84 | return 1; | ||
85 | } | ||
86 | } | ||
87 | EXPORT_SYMBOL(mISDN_FsmEvent); | ||
88 | |||
89 | void | ||
90 | mISDN_FsmChangeState(struct FsmInst *fi, int newstate) | ||
91 | { | ||
92 | fi->state = newstate; | ||
93 | if (fi->debug) | ||
94 | fi->printdebug(fi, "ChangeState %s", | ||
95 | fi->fsm->strState[newstate]); | ||
96 | } | ||
97 | EXPORT_SYMBOL(mISDN_FsmChangeState); | ||
98 | |||
99 | static void | ||
100 | FsmExpireTimer(struct FsmTimer *ft) | ||
101 | { | ||
102 | #if FSM_TIMER_DEBUG | ||
103 | if (ft->fi->debug) | ||
104 | ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); | ||
105 | #endif | ||
106 | mISDN_FsmEvent(ft->fi, ft->event, ft->arg); | ||
107 | } | ||
108 | |||
109 | void | ||
110 | mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) | ||
111 | { | ||
112 | ft->fi = fi; | ||
113 | ft->tl.function = (void *) FsmExpireTimer; | ||
114 | ft->tl.data = (long) ft; | ||
115 | #if FSM_TIMER_DEBUG | ||
116 | if (ft->fi->debug) | ||
117 | ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft); | ||
118 | #endif | ||
119 | init_timer(&ft->tl); | ||
120 | } | ||
121 | EXPORT_SYMBOL(mISDN_FsmInitTimer); | ||
122 | |||
123 | void | ||
124 | mISDN_FsmDelTimer(struct FsmTimer *ft, int where) | ||
125 | { | ||
126 | #if FSM_TIMER_DEBUG | ||
127 | if (ft->fi->debug) | ||
128 | ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", | ||
129 | (long) ft, where); | ||
130 | #endif | ||
131 | del_timer(&ft->tl); | ||
132 | } | ||
133 | EXPORT_SYMBOL(mISDN_FsmDelTimer); | ||
134 | |||
135 | int | ||
136 | mISDN_FsmAddTimer(struct FsmTimer *ft, | ||
137 | int millisec, int event, void *arg, int where) | ||
138 | { | ||
139 | |||
140 | #if FSM_TIMER_DEBUG | ||
141 | if (ft->fi->debug) | ||
142 | ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d", | ||
143 | (long) ft, millisec, where); | ||
144 | #endif | ||
145 | |||
146 | if (timer_pending(&ft->tl)) { | ||
147 | if (ft->fi->debug) { | ||
148 | printk(KERN_WARNING | ||
149 | "mISDN_FsmAddTimer: timer already active!\n"); | ||
150 | ft->fi->printdebug(ft->fi, | ||
151 | "mISDN_FsmAddTimer already active!"); | ||
152 | } | ||
153 | return -1; | ||
154 | } | ||
155 | init_timer(&ft->tl); | ||
156 | ft->event = event; | ||
157 | ft->arg = arg; | ||
158 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
159 | add_timer(&ft->tl); | ||
160 | return 0; | ||
161 | } | ||
162 | EXPORT_SYMBOL(mISDN_FsmAddTimer); | ||
163 | |||
164 | void | ||
165 | mISDN_FsmRestartTimer(struct FsmTimer *ft, | ||
166 | int millisec, int event, void *arg, int where) | ||
167 | { | ||
168 | |||
169 | #if FSM_TIMER_DEBUG | ||
170 | if (ft->fi->debug) | ||
171 | ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d", | ||
172 | (long) ft, millisec, where); | ||
173 | #endif | ||
174 | |||
175 | if (timer_pending(&ft->tl)) | ||
176 | del_timer(&ft->tl); | ||
177 | init_timer(&ft->tl); | ||
178 | ft->event = event; | ||
179 | ft->arg = arg; | ||
180 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
181 | add_timer(&ft->tl); | ||
182 | } | ||
183 | EXPORT_SYMBOL(mISDN_FsmRestartTimer); | ||
diff --git a/drivers/isdn/mISDN/fsm.h b/drivers/isdn/mISDN/fsm.h new file mode 100644 index 000000000000..928f5be192c1 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Thanks to Jan den Ouden | ||
6 | * Fritz Elfert | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
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 | */ | ||
19 | |||
20 | #ifndef _MISDN_FSM_H | ||
21 | #define _MISDN_FSM_H | ||
22 | |||
23 | #include <linux/timer.h> | ||
24 | |||
25 | /* Statemachine */ | ||
26 | |||
27 | struct FsmInst; | ||
28 | |||
29 | typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); | ||
30 | |||
31 | struct Fsm { | ||
32 | FSMFNPTR *jumpmatrix; | ||
33 | int state_count, event_count; | ||
34 | char **strEvent, **strState; | ||
35 | }; | ||
36 | |||
37 | struct FsmInst { | ||
38 | struct Fsm *fsm; | ||
39 | int state; | ||
40 | int debug; | ||
41 | void *userdata; | ||
42 | int userint; | ||
43 | void (*printdebug) (struct FsmInst *, char *, ...); | ||
44 | }; | ||
45 | |||
46 | struct FsmNode { | ||
47 | int state, event; | ||
48 | void (*routine) (struct FsmInst *, int, void *); | ||
49 | }; | ||
50 | |||
51 | struct FsmTimer { | ||
52 | struct FsmInst *fi; | ||
53 | struct timer_list tl; | ||
54 | int event; | ||
55 | void *arg; | ||
56 | }; | ||
57 | |||
58 | extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int); | ||
59 | extern void mISDN_FsmFree(struct Fsm *); | ||
60 | extern int mISDN_FsmEvent(struct FsmInst *, int , void *); | ||
61 | extern void mISDN_FsmChangeState(struct FsmInst *, int); | ||
62 | extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *); | ||
63 | extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int); | ||
64 | extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int); | ||
65 | extern void mISDN_FsmDelTimer(struct FsmTimer *, int); | ||
66 | |||
67 | #endif | ||
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c new file mode 100644 index 000000000000..2596fba4e614 --- /dev/null +++ b/drivers/isdn/mISDN/hwchannel.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/mISDNhw.h> | ||
20 | |||
21 | static void | ||
22 | dchannel_bh(struct work_struct *ws) | ||
23 | { | ||
24 | struct dchannel *dch = container_of(ws, struct dchannel, workq); | ||
25 | struct sk_buff *skb; | ||
26 | int err; | ||
27 | |||
28 | if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) { | ||
29 | while ((skb = skb_dequeue(&dch->rqueue))) { | ||
30 | if (likely(dch->dev.D.peer)) { | ||
31 | err = dch->dev.D.recv(dch->dev.D.peer, skb); | ||
32 | if (err) | ||
33 | dev_kfree_skb(skb); | ||
34 | } else | ||
35 | dev_kfree_skb(skb); | ||
36 | } | ||
37 | } | ||
38 | if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { | ||
39 | if (dch->phfunc) | ||
40 | dch->phfunc(dch); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void | ||
45 | bchannel_bh(struct work_struct *ws) | ||
46 | { | ||
47 | struct bchannel *bch = container_of(ws, struct bchannel, workq); | ||
48 | struct sk_buff *skb; | ||
49 | int err; | ||
50 | |||
51 | if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { | ||
52 | while ((skb = skb_dequeue(&bch->rqueue))) { | ||
53 | if (bch->rcount >= 64) | ||
54 | printk(KERN_WARNING "B-channel %p receive " | ||
55 | "queue if full, but empties...\n", bch); | ||
56 | bch->rcount--; | ||
57 | if (likely(bch->ch.peer)) { | ||
58 | err = bch->ch.recv(bch->ch.peer, skb); | ||
59 | if (err) | ||
60 | dev_kfree_skb(skb); | ||
61 | } else | ||
62 | dev_kfree_skb(skb); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | int | ||
68 | mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) | ||
69 | { | ||
70 | test_and_set_bit(FLG_HDLC, &ch->Flags); | ||
71 | ch->maxlen = maxlen; | ||
72 | ch->hw = NULL; | ||
73 | ch->rx_skb = NULL; | ||
74 | ch->tx_skb = NULL; | ||
75 | ch->tx_idx = 0; | ||
76 | ch->phfunc = phf; | ||
77 | skb_queue_head_init(&ch->squeue); | ||
78 | skb_queue_head_init(&ch->rqueue); | ||
79 | INIT_LIST_HEAD(&ch->dev.bchannels); | ||
80 | INIT_WORK(&ch->workq, dchannel_bh); | ||
81 | return 0; | ||
82 | } | ||
83 | EXPORT_SYMBOL(mISDN_initdchannel); | ||
84 | |||
85 | int | ||
86 | mISDN_initbchannel(struct bchannel *ch, int maxlen) | ||
87 | { | ||
88 | ch->Flags = 0; | ||
89 | ch->maxlen = maxlen; | ||
90 | ch->hw = NULL; | ||
91 | ch->rx_skb = NULL; | ||
92 | ch->tx_skb = NULL; | ||
93 | ch->tx_idx = 0; | ||
94 | skb_queue_head_init(&ch->rqueue); | ||
95 | ch->rcount = 0; | ||
96 | ch->next_skb = NULL; | ||
97 | INIT_WORK(&ch->workq, bchannel_bh); | ||
98 | return 0; | ||
99 | } | ||
100 | EXPORT_SYMBOL(mISDN_initbchannel); | ||
101 | |||
102 | int | ||
103 | mISDN_freedchannel(struct dchannel *ch) | ||
104 | { | ||
105 | if (ch->tx_skb) { | ||
106 | dev_kfree_skb(ch->tx_skb); | ||
107 | ch->tx_skb = NULL; | ||
108 | } | ||
109 | if (ch->rx_skb) { | ||
110 | dev_kfree_skb(ch->rx_skb); | ||
111 | ch->rx_skb = NULL; | ||
112 | } | ||
113 | skb_queue_purge(&ch->squeue); | ||
114 | skb_queue_purge(&ch->rqueue); | ||
115 | flush_scheduled_work(); | ||
116 | return 0; | ||
117 | } | ||
118 | EXPORT_SYMBOL(mISDN_freedchannel); | ||
119 | |||
120 | int | ||
121 | mISDN_freebchannel(struct bchannel *ch) | ||
122 | { | ||
123 | if (ch->tx_skb) { | ||
124 | dev_kfree_skb(ch->tx_skb); | ||
125 | ch->tx_skb = NULL; | ||
126 | } | ||
127 | if (ch->rx_skb) { | ||
128 | dev_kfree_skb(ch->rx_skb); | ||
129 | ch->rx_skb = NULL; | ||
130 | } | ||
131 | if (ch->next_skb) { | ||
132 | dev_kfree_skb(ch->next_skb); | ||
133 | ch->next_skb = NULL; | ||
134 | } | ||
135 | skb_queue_purge(&ch->rqueue); | ||
136 | ch->rcount = 0; | ||
137 | flush_scheduled_work(); | ||
138 | return 0; | ||
139 | } | ||
140 | EXPORT_SYMBOL(mISDN_freebchannel); | ||
141 | |||
142 | static inline u_int | ||
143 | get_sapi_tei(u_char *p) | ||
144 | { | ||
145 | u_int sapi, tei; | ||
146 | |||
147 | sapi = *p >> 2; | ||
148 | tei = p[1] >> 1; | ||
149 | return sapi | (tei << 8); | ||
150 | } | ||
151 | |||
152 | void | ||
153 | recv_Dchannel(struct dchannel *dch) | ||
154 | { | ||
155 | struct mISDNhead *hh; | ||
156 | |||
157 | if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ | ||
158 | dev_kfree_skb(dch->rx_skb); | ||
159 | dch->rx_skb = NULL; | ||
160 | return; | ||
161 | } | ||
162 | hh = mISDN_HEAD_P(dch->rx_skb); | ||
163 | hh->prim = PH_DATA_IND; | ||
164 | hh->id = get_sapi_tei(dch->rx_skb->data); | ||
165 | skb_queue_tail(&dch->rqueue, dch->rx_skb); | ||
166 | dch->rx_skb = NULL; | ||
167 | schedule_event(dch, FLG_RECVQUEUE); | ||
168 | } | ||
169 | EXPORT_SYMBOL(recv_Dchannel); | ||
170 | |||
171 | void | ||
172 | recv_Bchannel(struct bchannel *bch) | ||
173 | { | ||
174 | struct mISDNhead *hh; | ||
175 | |||
176 | hh = mISDN_HEAD_P(bch->rx_skb); | ||
177 | hh->prim = PH_DATA_IND; | ||
178 | hh->id = MISDN_ID_ANY; | ||
179 | if (bch->rcount >= 64) { | ||
180 | dev_kfree_skb(bch->rx_skb); | ||
181 | bch->rx_skb = NULL; | ||
182 | return; | ||
183 | } | ||
184 | bch->rcount++; | ||
185 | skb_queue_tail(&bch->rqueue, bch->rx_skb); | ||
186 | bch->rx_skb = NULL; | ||
187 | schedule_event(bch, FLG_RECVQUEUE); | ||
188 | } | ||
189 | EXPORT_SYMBOL(recv_Bchannel); | ||
190 | |||
191 | void | ||
192 | recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) | ||
193 | { | ||
194 | skb_queue_tail(&dch->rqueue, skb); | ||
195 | schedule_event(dch, FLG_RECVQUEUE); | ||
196 | } | ||
197 | EXPORT_SYMBOL(recv_Dchannel_skb); | ||
198 | |||
199 | void | ||
200 | recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) | ||
201 | { | ||
202 | if (bch->rcount >= 64) { | ||
203 | dev_kfree_skb(skb); | ||
204 | return; | ||
205 | } | ||
206 | bch->rcount++; | ||
207 | skb_queue_tail(&bch->rqueue, skb); | ||
208 | schedule_event(bch, FLG_RECVQUEUE); | ||
209 | } | ||
210 | EXPORT_SYMBOL(recv_Bchannel_skb); | ||
211 | |||
212 | static void | ||
213 | confirm_Dsend(struct dchannel *dch) | ||
214 | { | ||
215 | struct sk_buff *skb; | ||
216 | |||
217 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), | ||
218 | 0, NULL, GFP_ATOMIC); | ||
219 | if (!skb) { | ||
220 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
221 | mISDN_HEAD_ID(dch->tx_skb)); | ||
222 | return; | ||
223 | } | ||
224 | skb_queue_tail(&dch->rqueue, skb); | ||
225 | schedule_event(dch, FLG_RECVQUEUE); | ||
226 | } | ||
227 | |||
228 | int | ||
229 | get_next_dframe(struct dchannel *dch) | ||
230 | { | ||
231 | dch->tx_idx = 0; | ||
232 | dch->tx_skb = skb_dequeue(&dch->squeue); | ||
233 | if (dch->tx_skb) { | ||
234 | confirm_Dsend(dch); | ||
235 | return 1; | ||
236 | } | ||
237 | dch->tx_skb = NULL; | ||
238 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
239 | return 0; | ||
240 | } | ||
241 | EXPORT_SYMBOL(get_next_dframe); | ||
242 | |||
243 | void | ||
244 | confirm_Bsend(struct bchannel *bch) | ||
245 | { | ||
246 | struct sk_buff *skb; | ||
247 | |||
248 | if (bch->rcount >= 64) | ||
249 | return; | ||
250 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), | ||
251 | 0, NULL, GFP_ATOMIC); | ||
252 | if (!skb) { | ||
253 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
254 | mISDN_HEAD_ID(bch->tx_skb)); | ||
255 | return; | ||
256 | } | ||
257 | bch->rcount++; | ||
258 | skb_queue_tail(&bch->rqueue, skb); | ||
259 | schedule_event(bch, FLG_RECVQUEUE); | ||
260 | } | ||
261 | EXPORT_SYMBOL(confirm_Bsend); | ||
262 | |||
263 | int | ||
264 | get_next_bframe(struct bchannel *bch) | ||
265 | { | ||
266 | bch->tx_idx = 0; | ||
267 | if (test_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
268 | bch->tx_skb = bch->next_skb; | ||
269 | if (bch->tx_skb) { | ||
270 | bch->next_skb = NULL; | ||
271 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
272 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
273 | confirm_Bsend(bch); /* not for transparent */ | ||
274 | return 1; | ||
275 | } else { | ||
276 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
277 | printk(KERN_WARNING "B TX_NEXT without skb\n"); | ||
278 | } | ||
279 | } | ||
280 | bch->tx_skb = NULL; | ||
281 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
282 | return 0; | ||
283 | } | ||
284 | EXPORT_SYMBOL(get_next_bframe); | ||
285 | |||
286 | void | ||
287 | queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) | ||
288 | { | ||
289 | struct mISDNhead *hh; | ||
290 | |||
291 | if (!skb) { | ||
292 | _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); | ||
293 | } else { | ||
294 | if (ch->peer) { | ||
295 | hh = mISDN_HEAD_P(skb); | ||
296 | hh->prim = pr; | ||
297 | hh->id = id; | ||
298 | if (!ch->recv(ch->peer, skb)) | ||
299 | return; | ||
300 | } | ||
301 | dev_kfree_skb(skb); | ||
302 | } | ||
303 | } | ||
304 | EXPORT_SYMBOL(queue_ch_frame); | ||
305 | |||
306 | int | ||
307 | dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) | ||
308 | { | ||
309 | /* check oversize */ | ||
310 | if (skb->len <= 0) { | ||
311 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
312 | return -EINVAL; | ||
313 | } | ||
314 | if (skb->len > ch->maxlen) { | ||
315 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
316 | __func__, skb->len, ch->maxlen); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | /* HW lock must be obtained */ | ||
320 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
321 | skb_queue_tail(&ch->squeue, skb); | ||
322 | return 0; | ||
323 | } else { | ||
324 | /* write to fifo */ | ||
325 | ch->tx_skb = skb; | ||
326 | ch->tx_idx = 0; | ||
327 | return 1; | ||
328 | } | ||
329 | } | ||
330 | EXPORT_SYMBOL(dchannel_senddata); | ||
331 | |||
332 | int | ||
333 | bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) | ||
334 | { | ||
335 | |||
336 | /* check oversize */ | ||
337 | if (skb->len <= 0) { | ||
338 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | if (skb->len > ch->maxlen) { | ||
342 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
343 | __func__, skb->len, ch->maxlen); | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | /* HW lock must be obtained */ | ||
347 | /* check for pending next_skb */ | ||
348 | if (ch->next_skb) { | ||
349 | printk(KERN_WARNING | ||
350 | "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", | ||
351 | __func__, skb->len, ch->next_skb->len); | ||
352 | return -EBUSY; | ||
353 | } | ||
354 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
355 | test_and_set_bit(FLG_TX_NEXT, &ch->Flags); | ||
356 | ch->next_skb = skb; | ||
357 | return 0; | ||
358 | } else { | ||
359 | /* write to fifo */ | ||
360 | ch->tx_skb = skb; | ||
361 | ch->tx_idx = 0; | ||
362 | return 1; | ||
363 | } | ||
364 | } | ||
365 | EXPORT_SYMBOL(bchannel_senddata); | ||
diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h new file mode 100644 index 000000000000..a23d575449f6 --- /dev/null +++ b/drivers/isdn/mISDN/l1oip.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * see notice in l1oip.c | ||
3 | */ | ||
4 | |||
5 | /* debugging */ | ||
6 | #define DEBUG_L1OIP_INIT 0x00010000 | ||
7 | #define DEBUG_L1OIP_SOCKET 0x00020000 | ||
8 | #define DEBUG_L1OIP_MGR 0x00040000 | ||
9 | #define DEBUG_L1OIP_MSG 0x00080000 | ||
10 | |||
11 | /* enable to disorder received bchannels by sequence 2143658798... */ | ||
12 | /* | ||
13 | #define REORDER_DEBUG | ||
14 | */ | ||
15 | |||
16 | /* frames */ | ||
17 | #define L1OIP_MAX_LEN 2048 /* max packet size form l2 */ | ||
18 | #define L1OIP_MAX_PERFRAME 1400 /* max data size in one frame */ | ||
19 | |||
20 | |||
21 | /* timers */ | ||
22 | #define L1OIP_KEEPALIVE 15 | ||
23 | #define L1OIP_TIMEOUT 65 | ||
24 | |||
25 | |||
26 | /* socket */ | ||
27 | #define L1OIP_DEFAULTPORT 931 | ||
28 | |||
29 | |||
30 | /* channel structure */ | ||
31 | struct l1oip_chan { | ||
32 | struct dchannel *dch; | ||
33 | struct bchannel *bch; | ||
34 | u32 tx_counter; /* counts xmit bytes/packets */ | ||
35 | u32 rx_counter; /* counts recv bytes/packets */ | ||
36 | u32 codecstate; /* used by codec to save data */ | ||
37 | #ifdef REORDER_DEBUG | ||
38 | int disorder_flag; | ||
39 | struct sk_buff *disorder_skb; | ||
40 | u32 disorder_cnt; | ||
41 | #endif | ||
42 | }; | ||
43 | |||
44 | |||
45 | /* card structure */ | ||
46 | struct l1oip { | ||
47 | struct list_head list; | ||
48 | |||
49 | /* card */ | ||
50 | int registered; /* if registered with mISDN */ | ||
51 | char name[MISDN_MAX_IDLEN]; | ||
52 | int idx; /* card index */ | ||
53 | int pri; /* 1=pri, 0=bri */ | ||
54 | int d_idx; /* current dchannel number */ | ||
55 | int b_num; /* number of bchannels */ | ||
56 | u32 id; /* id of connection */ | ||
57 | int ondemand; /* if transmis. is on demand */ | ||
58 | int bundle; /* bundle channels in one frm */ | ||
59 | int codec; /* codec to use for transmis. */ | ||
60 | int limit; /* limit number of bchannels */ | ||
61 | |||
62 | /* timer */ | ||
63 | struct timer_list keep_tl; | ||
64 | struct timer_list timeout_tl; | ||
65 | int timeout_on; | ||
66 | struct work_struct workq; | ||
67 | |||
68 | /* socket */ | ||
69 | struct socket *socket; /* if set, socket is created */ | ||
70 | struct completion socket_complete;/* completion of sock thread */ | ||
71 | struct task_struct *socket_thread; | ||
72 | spinlock_t socket_lock; /* access sock outside thread */ | ||
73 | u32 remoteip; /* if all set, ip is assigned */ | ||
74 | u16 localport; /* must always be set */ | ||
75 | u16 remoteport; /* must always be set */ | ||
76 | struct sockaddr_in sin_local; /* local socket name */ | ||
77 | struct sockaddr_in sin_remote; /* remote socket name */ | ||
78 | struct msghdr sendmsg; /* ip message to send */ | ||
79 | struct iovec sendiov; /* iov for message */ | ||
80 | |||
81 | /* frame */ | ||
82 | struct l1oip_chan chan[128]; /* channel instances */ | ||
83 | }; | ||
84 | |||
85 | extern int l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state); | ||
86 | extern int l1oip_4bit_to_law(u8 *data, int len, u8 *result); | ||
87 | extern int l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result); | ||
88 | extern int l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result); | ||
89 | extern void l1oip_4bit_free(void); | ||
90 | extern int l1oip_4bit_alloc(int ulaw); | ||
91 | |||
diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c new file mode 100644 index 000000000000..a2dc4570ef43 --- /dev/null +++ b/drivers/isdn/mISDN/l1oip_codec.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | |||
3 | * l1oip_codec.c generic codec using lookup table | ||
4 | * -> conversion from a-Law to u-Law | ||
5 | * -> conversion from u-Law to a-Law | ||
6 | * -> compression by reducing the number of sample resolution to 4 | ||
7 | * | ||
8 | * NOTE: It is not compatible with any standard codec like ADPCM. | ||
9 | * | ||
10 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
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, or (at your option) | ||
15 | * 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 | |||
28 | /* | ||
29 | |||
30 | How the codec works: | ||
31 | -------------------- | ||
32 | |||
33 | The volume is increased to increase the dynamic range of the audio signal. | ||
34 | Each sample is converted to a-LAW with only 16 steps of level resolution. | ||
35 | A pair of two samples are stored in one byte. | ||
36 | |||
37 | The first byte is stored in the upper bits, the second byte is stored in the | ||
38 | lower bits. | ||
39 | |||
40 | To speed up compression and decompression, two lookup tables are formed: | ||
41 | |||
42 | - 16 bits index for two samples (law encoded) with 8 bit compressed result. | ||
43 | - 8 bits index for one compressed data with 16 bits decompressed result. | ||
44 | |||
45 | NOTE: The bytes are handled as they are law-encoded. | ||
46 | |||
47 | */ | ||
48 | |||
49 | #include <linux/vmalloc.h> | ||
50 | #include <linux/mISDNif.h> | ||
51 | #include "core.h" | ||
52 | |||
53 | /* definitions of codec. don't use calculations, code may run slower. */ | ||
54 | |||
55 | static u8 *table_com; | ||
56 | static u16 *table_dec; | ||
57 | |||
58 | |||
59 | /* alaw -> ulaw */ | ||
60 | static u8 alaw_to_ulaw[256] = | ||
61 | { | ||
62 | 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, | ||
63 | 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, | ||
64 | 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, | ||
65 | 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, | ||
66 | 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, | ||
67 | 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, | ||
68 | 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, | ||
69 | 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, | ||
70 | 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, | ||
71 | 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, | ||
72 | 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, | ||
73 | 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, | ||
74 | 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, | ||
75 | 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, | ||
76 | 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, | ||
77 | 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, | ||
78 | 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, | ||
79 | 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, | ||
80 | 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, | ||
81 | 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, | ||
82 | 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, | ||
83 | 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, | ||
84 | 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, | ||
85 | 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, | ||
86 | 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, | ||
87 | 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, | ||
88 | 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, | ||
89 | 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, | ||
90 | 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, | ||
91 | 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, | ||
92 | 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, | ||
93 | 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 | ||
94 | }; | ||
95 | |||
96 | /* ulaw -> alaw */ | ||
97 | static u8 ulaw_to_alaw[256] = | ||
98 | { | ||
99 | 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, | ||
100 | 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, | ||
101 | 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, | ||
102 | 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, | ||
103 | 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, | ||
104 | 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, | ||
105 | 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, | ||
106 | 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, | ||
107 | 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, | ||
108 | 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, | ||
109 | 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, | ||
110 | 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, | ||
111 | 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, | ||
112 | 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, | ||
113 | 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, | ||
114 | 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, | ||
115 | 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, | ||
116 | 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, | ||
117 | 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, | ||
118 | 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, | ||
119 | 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, | ||
120 | 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, | ||
121 | 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, | ||
122 | 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, | ||
123 | 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, | ||
124 | 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, | ||
125 | 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, | ||
126 | 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, | ||
127 | 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, | ||
128 | 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, | ||
129 | 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, | ||
130 | 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a | ||
131 | }; | ||
132 | |||
133 | /* alaw -> 4bit compression */ | ||
134 | static u8 alaw_to_4bit[256] = { | ||
135 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
136 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
137 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
138 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
139 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
140 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
141 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
142 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
143 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
144 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
145 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0d, 0x02, | ||
146 | 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
147 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
148 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
149 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
150 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
151 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
152 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
153 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
154 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
155 | 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
156 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x01, 0x0a, 0x05, | ||
157 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
158 | 0x0d, 0x02, 0x09, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
159 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
160 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
161 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
162 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
163 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
164 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
165 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
166 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
167 | }; | ||
168 | |||
169 | /* 4bit -> alaw decompression */ | ||
170 | static u8 _4bit_to_alaw[16] = { | ||
171 | 0x5d, 0x51, 0xd9, 0xd7, 0x5f, 0x53, 0xa3, 0x4b, | ||
172 | 0x2a, 0x3a, 0x22, 0x2e, 0x26, 0x56, 0x20, 0x2c, | ||
173 | }; | ||
174 | |||
175 | /* ulaw -> 4bit compression */ | ||
176 | static u8 ulaw_to_4bit[256] = { | ||
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
181 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
182 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
183 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | ||
184 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | ||
185 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, | ||
186 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, | ||
187 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, | ||
188 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, | ||
189 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, | ||
190 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, | ||
191 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, | ||
192 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, | ||
193 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
194 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
195 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
196 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
197 | 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, | ||
198 | 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, | ||
199 | 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
200 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
201 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, | ||
202 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, | ||
203 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, | ||
204 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, | ||
205 | 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, | ||
206 | 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, | ||
207 | 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
208 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
209 | }; | ||
210 | |||
211 | /* 4bit -> ulaw decompression */ | ||
212 | static u8 _4bit_to_ulaw[16] = { | ||
213 | 0x11, 0x21, 0x31, 0x40, 0x4e, 0x5c, 0x68, 0x71, | ||
214 | 0xfe, 0xef, 0xe7, 0xdb, 0xcd, 0xbf, 0xaf, 0x9f, | ||
215 | }; | ||
216 | |||
217 | |||
218 | /* | ||
219 | * Compresses data to the result buffer | ||
220 | * The result size must be at least half of the input buffer. | ||
221 | * The number of samples also must be even! | ||
222 | */ | ||
223 | int | ||
224 | l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state) | ||
225 | { | ||
226 | int ii, i = 0, o = 0; | ||
227 | |||
228 | if (!len) | ||
229 | return 0; | ||
230 | |||
231 | /* send saved byte and first input byte */ | ||
232 | if (*state) { | ||
233 | *result++ = table_com[(((*state)<<8)&0xff00) | (*data++)]; | ||
234 | len--; | ||
235 | o++; | ||
236 | } | ||
237 | |||
238 | ii = len >> 1; | ||
239 | |||
240 | while (i < ii) { | ||
241 | *result++ = table_com[(data[0]<<8) | (data[1])]; | ||
242 | data += 2; | ||
243 | i++; | ||
244 | o++; | ||
245 | } | ||
246 | |||
247 | /* if len has an odd number, we save byte for next call */ | ||
248 | if (len & 1) | ||
249 | *state = 0x100 + *data; | ||
250 | else | ||
251 | *state = 0; | ||
252 | |||
253 | return o; | ||
254 | } | ||
255 | |||
256 | /* Decompress data to the result buffer | ||
257 | * The result size must be the number of sample in packet. (2 * input data) | ||
258 | * The number of samples in the result are even! | ||
259 | */ | ||
260 | int | ||
261 | l1oip_4bit_to_law(u8 *data, int len, u8 *result) | ||
262 | { | ||
263 | int i = 0; | ||
264 | u16 r; | ||
265 | |||
266 | while (i < len) { | ||
267 | r = table_dec[*data++]; | ||
268 | *result++ = r>>8; | ||
269 | *result++ = r; | ||
270 | i++; | ||
271 | } | ||
272 | |||
273 | return len << 1; | ||
274 | } | ||
275 | |||
276 | |||
277 | /* | ||
278 | * law conversion | ||
279 | */ | ||
280 | int | ||
281 | l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result) | ||
282 | { | ||
283 | int i = 0; | ||
284 | |||
285 | while (i < len) { | ||
286 | *result++ = alaw_to_ulaw[*data++]; | ||
287 | i++; | ||
288 | } | ||
289 | |||
290 | return len; | ||
291 | } | ||
292 | |||
293 | int | ||
294 | l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result) | ||
295 | { | ||
296 | int i = 0; | ||
297 | |||
298 | while (i < len) { | ||
299 | *result++ = ulaw_to_alaw[*data++]; | ||
300 | i++; | ||
301 | } | ||
302 | |||
303 | return len; | ||
304 | } | ||
305 | |||
306 | |||
307 | /* | ||
308 | * generate/free compression and decompression table | ||
309 | */ | ||
310 | void | ||
311 | l1oip_4bit_free(void) | ||
312 | { | ||
313 | if (table_dec) | ||
314 | vfree(table_dec); | ||
315 | if (table_com) | ||
316 | vfree(table_com); | ||
317 | table_com = NULL; | ||
318 | table_dec = NULL; | ||
319 | } | ||
320 | |||
321 | int | ||
322 | l1oip_4bit_alloc(int ulaw) | ||
323 | { | ||
324 | int i1, i2, c, sample; | ||
325 | |||
326 | /* in case, it is called again */ | ||
327 | if (table_dec) | ||
328 | return 0; | ||
329 | |||
330 | /* alloc conversion tables */ | ||
331 | table_com = vmalloc(65536); | ||
332 | table_dec = vmalloc(512); | ||
333 | if (!table_com | !table_dec) { | ||
334 | l1oip_4bit_free(); | ||
335 | return -ENOMEM; | ||
336 | } | ||
337 | memset(table_com, 0, 65536); | ||
338 | memset(table_dec, 0, 512); | ||
339 | /* generate compression table */ | ||
340 | i1 = 0; | ||
341 | while (i1 < 256) { | ||
342 | if (ulaw) | ||
343 | c = ulaw_to_4bit[i1]; | ||
344 | else | ||
345 | c = alaw_to_4bit[i1]; | ||
346 | i2 = 0; | ||
347 | while (i2 < 256) { | ||
348 | table_com[(i1<<8) | i2] |= (c<<4); | ||
349 | table_com[(i2<<8) | i1] |= c; | ||
350 | i2++; | ||
351 | } | ||
352 | i1++; | ||
353 | } | ||
354 | |||
355 | /* generate decompression table */ | ||
356 | i1 = 0; | ||
357 | while (i1 < 16) { | ||
358 | if (ulaw) | ||
359 | sample = _4bit_to_ulaw[i1]; | ||
360 | else | ||
361 | sample = _4bit_to_alaw[i1]; | ||
362 | i2 = 0; | ||
363 | while (i2 < 16) { | ||
364 | table_dec[(i1<<4) | i2] |= (sample<<8); | ||
365 | table_dec[(i2<<4) | i1] |= sample; | ||
366 | i2++; | ||
367 | } | ||
368 | i1++; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | |||
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c new file mode 100644 index 000000000000..155b99780c4f --- /dev/null +++ b/drivers/isdn/mISDN/l1oip_core.c | |||
@@ -0,0 +1,1518 @@ | |||
1 | /* | ||
2 | |||
3 | * l1oip.c low level driver for tunneling layer 1 over IP | ||
4 | * | ||
5 | * NOTE: It is not compatible with TDMoIP nor "ISDN over IP". | ||
6 | * | ||
7 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
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 as published by | ||
11 | * the Free Software Foundation; either version 2, or (at your option) | ||
12 | * any later version. | ||
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 | /* module parameters: | ||
26 | * type: | ||
27 | Value 1 = BRI | ||
28 | Value 2 = PRI | ||
29 | Value 3 = BRI (multi channel frame, not supported yet) | ||
30 | Value 4 = PRI (multi channel frame, not supported yet) | ||
31 | A multi channel frame reduces overhead to a single frame for all | ||
32 | b-channels, but increases delay. | ||
33 | (NOTE: Multi channel frames are not implemented yet.) | ||
34 | |||
35 | * codec: | ||
36 | Value 0 = transparent (default) | ||
37 | Value 1 = transfer ALAW | ||
38 | Value 2 = transfer ULAW | ||
39 | Value 3 = transfer generic 4 bit compression. | ||
40 | |||
41 | * ulaw: | ||
42 | 0 = we use a-Law (default) | ||
43 | 1 = we use u-Law | ||
44 | |||
45 | * limit: | ||
46 | limitation of B-channels to control bandwidth (1...126) | ||
47 | BRI: 1 or 2 | ||
48 | PRI: 1-30, 31-126 (126, because dchannel ist not counted here) | ||
49 | Also limited ressources are used for stack, resulting in less channels. | ||
50 | It is possible to have more channels than 30 in PRI mode, this must | ||
51 | be supported by the application. | ||
52 | |||
53 | * ip: | ||
54 | byte representation of remote ip address (127.0.0.1 -> 127,0,0,1) | ||
55 | If not given or four 0, no remote address is set. | ||
56 | For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1) | ||
57 | |||
58 | * port: | ||
59 | port number (local interface) | ||
60 | If not given or 0, port 931 is used for fist instance, 932 for next... | ||
61 | For multiple interfaces, different ports must be given. | ||
62 | |||
63 | * remoteport: | ||
64 | port number (remote interface) | ||
65 | If not given or 0, remote port equals local port | ||
66 | For multiple interfaces on equal sites, different ports must be given. | ||
67 | |||
68 | * ondemand: | ||
69 | 0 = fixed (always transmit packets, even when remote side timed out) | ||
70 | 1 = on demand (only transmit packets, when remote side is detected) | ||
71 | the default is 0 | ||
72 | NOTE: ID must also be set for on demand. | ||
73 | |||
74 | * id: | ||
75 | optional value to identify frames. This value must be equal on both | ||
76 | peers and should be random. If omitted or 0, no ID is transmitted. | ||
77 | |||
78 | * debug: | ||
79 | NOTE: only one debug value must be given for all cards | ||
80 | enable debugging (see l1oip.h for debug options) | ||
81 | |||
82 | |||
83 | Special mISDN controls: | ||
84 | |||
85 | op = MISDN_CTRL_SETPEER* | ||
86 | p1 = bytes 0-3 : remote IP address in network order (left element first) | ||
87 | p2 = bytes 1-2 : remote port in network order (high byte first) | ||
88 | optional: | ||
89 | p2 = bytes 3-4 : local port in network order (high byte first) | ||
90 | |||
91 | op = MISDN_CTRL_UNSETPEER* | ||
92 | |||
93 | * Use l1oipctrl for comfortable setting or removing ip address. | ||
94 | (Layer 1 Over IP CTRL) | ||
95 | |||
96 | |||
97 | L1oIP-Protocol | ||
98 | -------------- | ||
99 | |||
100 | Frame Header: | ||
101 | |||
102 | 7 6 5 4 3 2 1 0 | ||
103 | +---------------+ | ||
104 | |Ver|T|I|Coding | | ||
105 | +---------------+ | ||
106 | | ID byte 3 * | | ||
107 | +---------------+ | ||
108 | | ID byte 2 * | | ||
109 | +---------------+ | ||
110 | | ID byte 1 * | | ||
111 | +---------------+ | ||
112 | | ID byte 0 * | | ||
113 | +---------------+ | ||
114 | |M| Channel | | ||
115 | +---------------+ | ||
116 | | Length * | | ||
117 | +---------------+ | ||
118 | | Time Base MSB | | ||
119 | +---------------+ | ||
120 | | Time Base LSB | | ||
121 | +---------------+ | ||
122 | | Data.... | | ||
123 | |||
124 | ... | ||
125 | |||
126 | | | | ||
127 | +---------------+ | ||
128 | |M| Channel | | ||
129 | +---------------+ | ||
130 | | Length * | | ||
131 | +---------------+ | ||
132 | | Time Base MSB | | ||
133 | +---------------+ | ||
134 | | Time Base LSB | | ||
135 | +---------------+ | ||
136 | | Data.... | | ||
137 | |||
138 | ... | ||
139 | |||
140 | |||
141 | * Only included in some cases. | ||
142 | |||
143 | - Ver = Version | ||
144 | If version is missmatch, the frame must be ignored. | ||
145 | |||
146 | - T = Type of interface | ||
147 | Must be 0 for S0 or 1 for E1. | ||
148 | |||
149 | - I = Id present | ||
150 | If bit is set, four ID bytes are included in frame. | ||
151 | |||
152 | - ID = Connection ID | ||
153 | Additional ID to prevent Denial of Service attacs. Also it prevents hijacking | ||
154 | connections with dynamic IP. The ID should be random and must not be 0. | ||
155 | |||
156 | - Coding = Type of codec | ||
157 | Must be 0 for no transcoding. Also for D-channel and other HDLC frames. | ||
158 | 1 and 2 are reserved for explicitly use of a-LAW or u-LAW codec. | ||
159 | 3 is used for generic table compressor. | ||
160 | |||
161 | - M = More channels to come. If this flag is 1, the following byte contains | ||
162 | the length of the channel data. After the data block, the next channel will | ||
163 | be defined. The flag for the last channel block (or if only one channel is | ||
164 | transmitted), must be 0 and no length is given. | ||
165 | |||
166 | - Channel = Channel number | ||
167 | 0 reserved | ||
168 | 1-3 channel data for S0 (3 is D-channel) | ||
169 | 1-31 channel data for E1 (16 is D-channel) | ||
170 | 32-127 channel data for extended E1 (16 is D-channel) | ||
171 | |||
172 | - The length is used if the M-flag is 1. It is used to find the next channel | ||
173 | inside frame. | ||
174 | NOTE: A value of 0 equals 256 bytes of data. | ||
175 | -> For larger data blocks, a single frame must be used. | ||
176 | -> For larger streams, a single frame or multiple blocks with same channel ID | ||
177 | must be used. | ||
178 | |||
179 | - Time Base = Timestamp of first sample in frame | ||
180 | The "Time Base" is used to rearange packets and to detect packet loss. | ||
181 | The 16 bits are sent in network order (MSB first) and count 1/8000 th of a | ||
182 | second. This causes a wrap arround each 8,192 seconds. There is no requirement | ||
183 | for the initial "Time Base", but 0 should be used for the first packet. | ||
184 | In case of HDLC data, this timestamp counts the packet or byte number. | ||
185 | |||
186 | |||
187 | Two Timers: | ||
188 | |||
189 | After initialisation, a timer of 15 seconds is started. Whenever a packet is | ||
190 | transmitted, the timer is reset to 15 seconds again. If the timer expires, an | ||
191 | empty packet is transmitted. This keep the connection alive. | ||
192 | |||
193 | When a valid packet is received, a timer 65 seconds is started. The interface | ||
194 | become ACTIVE. If the timer expires, the interface becomes INACTIVE. | ||
195 | |||
196 | |||
197 | Dynamic IP handling: | ||
198 | |||
199 | To allow dynamic IP, the ID must be non 0. In this case, any packet with the | ||
200 | correct port number and ID will be accepted. If the remote side changes its IP | ||
201 | the new IP is used for all transmitted packets until it changes again. | ||
202 | |||
203 | |||
204 | On Demand: | ||
205 | |||
206 | If the ondemand parameter is given, the remote IP is set to 0 on timeout. | ||
207 | This will stop keepalive traffic to remote. If the remote is online again, | ||
208 | traffic will continue to the remote address. This is usefull for road warriors. | ||
209 | This feature only works with ID set, otherwhise it is highly unsecure. | ||
210 | |||
211 | |||
212 | Socket and Thread | ||
213 | ----------------- | ||
214 | |||
215 | The complete socket opening and closing is done by a thread. | ||
216 | When the thread opened a socket, the hc->socket descriptor is set. Whenever a | ||
217 | packet shall be sent to the socket, the hc->socket must be checked wheter not | ||
218 | NULL. To prevent change in socket descriptor, the hc->socket_lock must be used. | ||
219 | To change the socket, a recall of l1oip_socket_open() will safely kill the | ||
220 | socket process and create a new one. | ||
221 | |||
222 | */ | ||
223 | |||
224 | #define L1OIP_VERSION 0 /* 0...3 */ | ||
225 | |||
226 | #include <linux/module.h> | ||
227 | #include <linux/delay.h> | ||
228 | #include <linux/mISDNif.h> | ||
229 | #include <linux/mISDNhw.h> | ||
230 | #include <linux/mISDNdsp.h> | ||
231 | #include <linux/init.h> | ||
232 | #include <linux/in.h> | ||
233 | #include <linux/inet.h> | ||
234 | #include <linux/workqueue.h> | ||
235 | #include <linux/kthread.h> | ||
236 | #include <net/sock.h> | ||
237 | #include "core.h" | ||
238 | #include "l1oip.h" | ||
239 | |||
240 | static const char *l1oip_revision = "2.00"; | ||
241 | |||
242 | static int l1oip_cnt; | ||
243 | static spinlock_t l1oip_lock; | ||
244 | static struct list_head l1oip_ilist; | ||
245 | |||
246 | #define MAX_CARDS 16 | ||
247 | static u_int type[MAX_CARDS]; | ||
248 | static u_int codec[MAX_CARDS]; | ||
249 | static u_int ip[MAX_CARDS*4]; | ||
250 | static u_int port[MAX_CARDS]; | ||
251 | static u_int remoteport[MAX_CARDS]; | ||
252 | static u_int ondemand[MAX_CARDS]; | ||
253 | static u_int limit[MAX_CARDS]; | ||
254 | static u_int id[MAX_CARDS]; | ||
255 | static int debug; | ||
256 | static int ulaw; | ||
257 | |||
258 | MODULE_AUTHOR("Andreas Eversberg"); | ||
259 | MODULE_LICENSE("GPL"); | ||
260 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | ||
261 | module_param_array(codec, uint, NULL, S_IRUGO | S_IWUSR); | ||
262 | module_param_array(ip, uint, NULL, S_IRUGO | S_IWUSR); | ||
263 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | ||
264 | module_param_array(remoteport, uint, NULL, S_IRUGO | S_IWUSR); | ||
265 | module_param_array(ondemand, uint, NULL, S_IRUGO | S_IWUSR); | ||
266 | module_param_array(limit, uint, NULL, S_IRUGO | S_IWUSR); | ||
267 | module_param_array(id, uint, NULL, S_IRUGO | S_IWUSR); | ||
268 | module_param(ulaw, uint, S_IRUGO | S_IWUSR); | ||
269 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
270 | |||
271 | /* | ||
272 | * send a frame via socket, if open and restart timer | ||
273 | */ | ||
274 | static int | ||
275 | l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, | ||
276 | u16 timebase, u8 *buf, int len) | ||
277 | { | ||
278 | u8 *p; | ||
279 | int multi = 0; | ||
280 | u8 frame[len+32]; | ||
281 | struct socket *socket = NULL; | ||
282 | mm_segment_t oldfs; | ||
283 | |||
284 | if (debug & DEBUG_L1OIP_MSG) | ||
285 | printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", | ||
286 | __func__, len); | ||
287 | |||
288 | p = frame; | ||
289 | |||
290 | /* restart timer */ | ||
291 | if ((int)(hc->keep_tl.expires-jiffies) < 5*HZ) { | ||
292 | del_timer(&hc->keep_tl); | ||
293 | hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; | ||
294 | add_timer(&hc->keep_tl); | ||
295 | } else | ||
296 | hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; | ||
297 | |||
298 | if (debug & DEBUG_L1OIP_MSG) | ||
299 | printk(KERN_DEBUG "%s: resetting timer\n", __func__); | ||
300 | |||
301 | /* drop if we have no remote ip or port */ | ||
302 | if (!hc->sin_remote.sin_addr.s_addr || !hc->sin_remote.sin_port) { | ||
303 | if (debug & DEBUG_L1OIP_MSG) | ||
304 | printk(KERN_DEBUG "%s: dropping frame, because remote " | ||
305 | "IP is not set.\n", __func__); | ||
306 | return len; | ||
307 | } | ||
308 | |||
309 | /* assemble frame */ | ||
310 | *p++ = (L1OIP_VERSION<<6) /* version and coding */ | ||
311 | | (hc->pri?0x20:0x00) /* type */ | ||
312 | | (hc->id?0x10:0x00) /* id */ | ||
313 | | localcodec; | ||
314 | if (hc->id) { | ||
315 | *p++ = hc->id>>24; /* id */ | ||
316 | *p++ = hc->id>>16; | ||
317 | *p++ = hc->id>>8; | ||
318 | *p++ = hc->id; | ||
319 | } | ||
320 | *p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */ | ||
321 | if (multi == 1) | ||
322 | *p++ = len; /* length */ | ||
323 | *p++ = timebase>>8; /* time base */ | ||
324 | *p++ = timebase; | ||
325 | |||
326 | if (buf && len) { /* add data to frame */ | ||
327 | if (localcodec == 1 && ulaw) | ||
328 | l1oip_ulaw_to_alaw(buf, len, p); | ||
329 | else if (localcodec == 2 && !ulaw) | ||
330 | l1oip_alaw_to_ulaw(buf, len, p); | ||
331 | else if (localcodec == 3) | ||
332 | len = l1oip_law_to_4bit(buf, len, p, | ||
333 | &hc->chan[channel].codecstate); | ||
334 | else | ||
335 | memcpy(p, buf, len); | ||
336 | } | ||
337 | len += p - frame; | ||
338 | |||
339 | /* check for socket in safe condition */ | ||
340 | spin_lock(&hc->socket_lock); | ||
341 | if (!hc->socket) { | ||
342 | spin_unlock(&hc->socket_lock); | ||
343 | return 0; | ||
344 | } | ||
345 | /* seize socket */ | ||
346 | socket = hc->socket; | ||
347 | hc->socket = NULL; | ||
348 | spin_unlock(&hc->socket_lock); | ||
349 | /* send packet */ | ||
350 | if (debug & DEBUG_L1OIP_MSG) | ||
351 | printk(KERN_DEBUG "%s: sending packet to socket (len " | ||
352 | "= %d)\n", __func__, len); | ||
353 | hc->sendiov.iov_base = frame; | ||
354 | hc->sendiov.iov_len = len; | ||
355 | oldfs = get_fs(); | ||
356 | set_fs(KERNEL_DS); | ||
357 | len = sock_sendmsg(socket, &hc->sendmsg, len); | ||
358 | set_fs(oldfs); | ||
359 | /* give socket back */ | ||
360 | hc->socket = socket; /* no locking required */ | ||
361 | |||
362 | return len; | ||
363 | } | ||
364 | |||
365 | |||
366 | /* | ||
367 | * receive channel data from socket | ||
368 | */ | ||
369 | static void | ||
370 | l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, | ||
371 | u8 *buf, int len) | ||
372 | { | ||
373 | struct sk_buff *nskb; | ||
374 | struct bchannel *bch; | ||
375 | struct dchannel *dch; | ||
376 | u8 *p; | ||
377 | u32 rx_counter; | ||
378 | |||
379 | if (len == 0) { | ||
380 | if (debug & DEBUG_L1OIP_MSG) | ||
381 | printk(KERN_DEBUG "%s: received empty keepalive data, " | ||
382 | "ignoring\n", __func__); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | if (debug & DEBUG_L1OIP_MSG) | ||
387 | printk(KERN_DEBUG "%s: received data, sending to mISDN (%d)\n", | ||
388 | __func__, len); | ||
389 | |||
390 | if (channel < 1 || channel > 127) { | ||
391 | printk(KERN_WARNING "%s: packet error - channel %d out of " | ||
392 | "range\n", __func__, channel); | ||
393 | return; | ||
394 | } | ||
395 | dch = hc->chan[channel].dch; | ||
396 | bch = hc->chan[channel].bch; | ||
397 | if (!dch && !bch) { | ||
398 | printk(KERN_WARNING "%s: packet error - channel %d not in " | ||
399 | "stack\n", __func__, channel); | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | /* prepare message */ | ||
404 | nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC); | ||
405 | if (!nskb) { | ||
406 | printk(KERN_ERR "%s: No mem for skb.\n", __func__); | ||
407 | return; | ||
408 | } | ||
409 | p = skb_put(nskb, (remotecodec == 3)?(len<<1):len); | ||
410 | |||
411 | if (remotecodec == 1 && ulaw) | ||
412 | l1oip_alaw_to_ulaw(buf, len, p); | ||
413 | else if (remotecodec == 2 && !ulaw) | ||
414 | l1oip_ulaw_to_alaw(buf, len, p); | ||
415 | else if (remotecodec == 3) | ||
416 | len = l1oip_4bit_to_law(buf, len, p); | ||
417 | else | ||
418 | memcpy(p, buf, len); | ||
419 | |||
420 | /* send message up */ | ||
421 | if (dch && len >= 2) { | ||
422 | dch->rx_skb = nskb; | ||
423 | recv_Dchannel(dch); | ||
424 | } | ||
425 | if (bch) { | ||
426 | /* expand 16 bit sequence number to 32 bit sequence number */ | ||
427 | rx_counter = hc->chan[channel].rx_counter; | ||
428 | if (((s16)(timebase - rx_counter)) >= 0) { | ||
429 | /* time has changed forward */ | ||
430 | if (timebase >= (rx_counter & 0xffff)) | ||
431 | rx_counter = | ||
432 | (rx_counter & 0xffff0000) | timebase; | ||
433 | else | ||
434 | rx_counter = ((rx_counter & 0xffff0000)+0x10000) | ||
435 | | timebase; | ||
436 | } else { | ||
437 | /* time has changed backwards */ | ||
438 | if (timebase < (rx_counter & 0xffff)) | ||
439 | rx_counter = | ||
440 | (rx_counter & 0xffff0000) | timebase; | ||
441 | else | ||
442 | rx_counter = ((rx_counter & 0xffff0000)-0x10000) | ||
443 | | timebase; | ||
444 | } | ||
445 | hc->chan[channel].rx_counter = rx_counter; | ||
446 | |||
447 | #ifdef REORDER_DEBUG | ||
448 | if (hc->chan[channel].disorder_flag) { | ||
449 | struct sk_buff *skb; | ||
450 | int cnt; | ||
451 | skb = hc->chan[channel].disorder_skb; | ||
452 | hc->chan[channel].disorder_skb = nskb; | ||
453 | nskb = skb; | ||
454 | cnt = hc->chan[channel].disorder_cnt; | ||
455 | hc->chan[channel].disorder_cnt = rx_counter; | ||
456 | rx_counter = cnt; | ||
457 | } | ||
458 | hc->chan[channel].disorder_flag ^= 1; | ||
459 | if (nskb) | ||
460 | #endif | ||
461 | queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); | ||
462 | } | ||
463 | } | ||
464 | |||
465 | |||
466 | /* | ||
467 | * parse frame and extract channel data | ||
468 | */ | ||
469 | static void | ||
470 | l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) | ||
471 | { | ||
472 | u32 id; | ||
473 | u8 channel; | ||
474 | u8 remotecodec; | ||
475 | u16 timebase; | ||
476 | int m, mlen; | ||
477 | int len_start = len; /* initial frame length */ | ||
478 | struct dchannel *dch = hc->chan[hc->d_idx].dch; | ||
479 | |||
480 | if (debug & DEBUG_L1OIP_MSG) | ||
481 | printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n", | ||
482 | __func__, len); | ||
483 | |||
484 | /* check lenght */ | ||
485 | if (len < 1+1+2) { | ||
486 | printk(KERN_WARNING "%s: packet error - length %d below " | ||
487 | "4 bytes\n", __func__, len); | ||
488 | return; | ||
489 | } | ||
490 | |||
491 | /* check version */ | ||
492 | if (((*buf)>>6) != L1OIP_VERSION) { | ||
493 | printk(KERN_WARNING "%s: packet error - unknown version %d\n", | ||
494 | __func__, buf[0]>>6); | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | /* check type */ | ||
499 | if (((*buf)&0x20) && !hc->pri) { | ||
500 | printk(KERN_WARNING "%s: packet error - received E1 packet " | ||
501 | "on S0 interface\n", __func__); | ||
502 | return; | ||
503 | } | ||
504 | if (!((*buf)&0x20) && hc->pri) { | ||
505 | printk(KERN_WARNING "%s: packet error - received S0 packet " | ||
506 | "on E1 interface\n", __func__); | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | /* get id flag */ | ||
511 | id = (*buf>>4)&1; | ||
512 | |||
513 | /* check coding */ | ||
514 | remotecodec = (*buf) & 0x0f; | ||
515 | if (remotecodec > 3) { | ||
516 | printk(KERN_WARNING "%s: packet error - remotecodec %d " | ||
517 | "unsupported\n", __func__, remotecodec); | ||
518 | return; | ||
519 | } | ||
520 | buf++; | ||
521 | len--; | ||
522 | |||
523 | /* check id */ | ||
524 | if (id) { | ||
525 | if (!hc->id) { | ||
526 | printk(KERN_WARNING "%s: packet error - packet has id " | ||
527 | "0x%x, but we have not\n", __func__, id); | ||
528 | return; | ||
529 | } | ||
530 | if (len < 4) { | ||
531 | printk(KERN_WARNING "%s: packet error - packet too " | ||
532 | "short for ID value\n", __func__); | ||
533 | return; | ||
534 | } | ||
535 | id = (*buf++) << 24; | ||
536 | id += (*buf++) << 16; | ||
537 | id += (*buf++) << 8; | ||
538 | id += (*buf++); | ||
539 | len -= 4; | ||
540 | |||
541 | if (id != hc->id) { | ||
542 | printk(KERN_WARNING "%s: packet error - ID mismatch, " | ||
543 | "got 0x%x, we 0x%x\n", | ||
544 | __func__, id, hc->id); | ||
545 | return; | ||
546 | } | ||
547 | } else { | ||
548 | if (hc->id) { | ||
549 | printk(KERN_WARNING "%s: packet error - packet has no " | ||
550 | "ID, but we have\n", __func__); | ||
551 | return; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | multiframe: | ||
556 | if (len < 1) { | ||
557 | printk(KERN_WARNING "%s: packet error - packet too short, " | ||
558 | "channel expected at position %d.\n", | ||
559 | __func__, len-len_start+1); | ||
560 | return; | ||
561 | } | ||
562 | |||
563 | /* get channel and multiframe flag */ | ||
564 | channel = *buf&0x7f; | ||
565 | m = *buf >> 7; | ||
566 | buf++; | ||
567 | len--; | ||
568 | |||
569 | /* check length on multiframe */ | ||
570 | if (m) { | ||
571 | if (len < 1) { | ||
572 | printk(KERN_WARNING "%s: packet error - packet too " | ||
573 | "short, length expected at position %d.\n", | ||
574 | __func__, len_start-len-1); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | mlen = *buf++; | ||
579 | len--; | ||
580 | if (mlen == 0) | ||
581 | mlen = 256; | ||
582 | if (len < mlen+3) { | ||
583 | printk(KERN_WARNING "%s: packet error - length %d at " | ||
584 | "position %d exceeds total length %d.\n", | ||
585 | __func__, mlen, len_start-len-1, len_start); | ||
586 | return; | ||
587 | } | ||
588 | if (len == mlen+3) { | ||
589 | printk(KERN_WARNING "%s: packet error - length %d at " | ||
590 | "position %d will not allow additional " | ||
591 | "packet.\n", | ||
592 | __func__, mlen, len_start-len+1); | ||
593 | return; | ||
594 | } | ||
595 | } else | ||
596 | mlen = len-2; /* single frame, substract timebase */ | ||
597 | |||
598 | if (len < 2) { | ||
599 | printk(KERN_WARNING "%s: packet error - packet too short, time " | ||
600 | "base expected at position %d.\n", | ||
601 | __func__, len-len_start+1); | ||
602 | return; | ||
603 | } | ||
604 | |||
605 | /* get time base */ | ||
606 | timebase = (*buf++) << 8; | ||
607 | timebase |= (*buf++); | ||
608 | len -= 2; | ||
609 | |||
610 | /* if inactive, we send up a PH_ACTIVATE and activate */ | ||
611 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
612 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
613 | printk(KERN_DEBUG "%s: interface become active due to " | ||
614 | "received packet\n", __func__); | ||
615 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
616 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
617 | NULL, GFP_ATOMIC); | ||
618 | } | ||
619 | |||
620 | /* distribute packet */ | ||
621 | l1oip_socket_recv(hc, remotecodec, channel, timebase, buf, mlen); | ||
622 | buf += mlen; | ||
623 | len -= mlen; | ||
624 | |||
625 | /* multiframe */ | ||
626 | if (m) | ||
627 | goto multiframe; | ||
628 | |||
629 | /* restart timer */ | ||
630 | if ((int)(hc->timeout_tl.expires-jiffies) < 5*HZ || !hc->timeout_on) { | ||
631 | hc->timeout_on = 1; | ||
632 | del_timer(&hc->timeout_tl); | ||
633 | hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; | ||
634 | add_timer(&hc->timeout_tl); | ||
635 | } else /* only adjust timer */ | ||
636 | hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; | ||
637 | |||
638 | /* if ip or source port changes */ | ||
639 | if ((hc->sin_remote.sin_addr.s_addr != sin->sin_addr.s_addr) | ||
640 | || (hc->sin_remote.sin_port != sin->sin_port)) { | ||
641 | if (debug & DEBUG_L1OIP_SOCKET) | ||
642 | printk(KERN_DEBUG "%s: remote address changes from " | ||
643 | "0x%08x to 0x%08x (port %d to %d)\n", __func__, | ||
644 | ntohl(hc->sin_remote.sin_addr.s_addr), | ||
645 | ntohl(sin->sin_addr.s_addr), | ||
646 | ntohs(hc->sin_remote.sin_port), | ||
647 | ntohs(sin->sin_port)); | ||
648 | hc->sin_remote.sin_addr.s_addr = sin->sin_addr.s_addr; | ||
649 | hc->sin_remote.sin_port = sin->sin_port; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | |||
654 | /* | ||
655 | * socket stuff | ||
656 | */ | ||
657 | static int | ||
658 | l1oip_socket_thread(void *data) | ||
659 | { | ||
660 | struct l1oip *hc = (struct l1oip *)data; | ||
661 | int ret = 0; | ||
662 | struct msghdr msg; | ||
663 | struct iovec iov; | ||
664 | mm_segment_t oldfs; | ||
665 | struct sockaddr_in sin_rx; | ||
666 | unsigned char recvbuf[1500]; | ||
667 | int recvlen; | ||
668 | struct socket *socket = NULL; | ||
669 | DECLARE_COMPLETION(wait); | ||
670 | |||
671 | /* make daemon */ | ||
672 | allow_signal(SIGTERM); | ||
673 | |||
674 | /* create socket */ | ||
675 | if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { | ||
676 | printk(KERN_ERR "%s: Failed to create socket.\n", __func__); | ||
677 | return -EIO; | ||
678 | } | ||
679 | |||
680 | /* set incoming address */ | ||
681 | hc->sin_local.sin_family = AF_INET; | ||
682 | hc->sin_local.sin_addr.s_addr = INADDR_ANY; | ||
683 | hc->sin_local.sin_port = htons((unsigned short)hc->localport); | ||
684 | |||
685 | /* set outgoing address */ | ||
686 | hc->sin_remote.sin_family = AF_INET; | ||
687 | hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip); | ||
688 | hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport); | ||
689 | |||
690 | /* bind to incomming port */ | ||
691 | if (socket->ops->bind(socket, (struct sockaddr *)&hc->sin_local, | ||
692 | sizeof(hc->sin_local))) { | ||
693 | printk(KERN_ERR "%s: Failed to bind socket to port %d.\n", | ||
694 | __func__, hc->localport); | ||
695 | ret = -EINVAL; | ||
696 | goto fail; | ||
697 | } | ||
698 | |||
699 | /* check sk */ | ||
700 | if (socket->sk == NULL) { | ||
701 | printk(KERN_ERR "%s: socket->sk == NULL\n", __func__); | ||
702 | ret = -EIO; | ||
703 | goto fail; | ||
704 | } | ||
705 | |||
706 | /* build receive message */ | ||
707 | msg.msg_name = &sin_rx; | ||
708 | msg.msg_namelen = sizeof(sin_rx); | ||
709 | msg.msg_control = NULL; | ||
710 | msg.msg_controllen = 0; | ||
711 | msg.msg_iov = &iov; | ||
712 | msg.msg_iovlen = 1; | ||
713 | |||
714 | /* build send message */ | ||
715 | hc->sendmsg.msg_name = &hc->sin_remote; | ||
716 | hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); | ||
717 | hc->sendmsg.msg_control = NULL; | ||
718 | hc->sendmsg.msg_controllen = 0; | ||
719 | hc->sendmsg.msg_iov = &hc->sendiov; | ||
720 | hc->sendmsg.msg_iovlen = 1; | ||
721 | |||
722 | /* give away socket */ | ||
723 | spin_lock(&hc->socket_lock); | ||
724 | hc->socket = socket; | ||
725 | spin_unlock(&hc->socket_lock); | ||
726 | |||
727 | /* read loop */ | ||
728 | if (debug & DEBUG_L1OIP_SOCKET) | ||
729 | printk(KERN_DEBUG "%s: socket created and open\n", | ||
730 | __func__); | ||
731 | while (!signal_pending(current)) { | ||
732 | iov.iov_base = recvbuf; | ||
733 | iov.iov_len = sizeof(recvbuf); | ||
734 | oldfs = get_fs(); | ||
735 | set_fs(KERNEL_DS); | ||
736 | recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0); | ||
737 | set_fs(oldfs); | ||
738 | if (recvlen > 0) { | ||
739 | l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); | ||
740 | } else { | ||
741 | if (debug & DEBUG_L1OIP_SOCKET) | ||
742 | printk(KERN_WARNING "%s: broken pipe on socket\n", | ||
743 | __func__); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | /* get socket back, check first if in use, maybe by send function */ | ||
748 | spin_lock(&hc->socket_lock); | ||
749 | /* if hc->socket is NULL, it is in use until it is given back */ | ||
750 | while (!hc->socket) { | ||
751 | spin_unlock(&hc->socket_lock); | ||
752 | schedule_timeout(HZ/10); | ||
753 | spin_lock(&hc->socket_lock); | ||
754 | } | ||
755 | hc->socket = NULL; | ||
756 | spin_unlock(&hc->socket_lock); | ||
757 | |||
758 | if (debug & DEBUG_L1OIP_SOCKET) | ||
759 | printk(KERN_DEBUG "%s: socket thread terminating\n", | ||
760 | __func__); | ||
761 | |||
762 | fail: | ||
763 | /* close socket */ | ||
764 | if (socket) | ||
765 | sock_release(socket); | ||
766 | |||
767 | /* if we got killed, signal completion */ | ||
768 | complete(&hc->socket_complete); | ||
769 | hc->socket_thread = NULL; /* show termination of thread */ | ||
770 | |||
771 | if (debug & DEBUG_L1OIP_SOCKET) | ||
772 | printk(KERN_DEBUG "%s: socket thread terminated\n", | ||
773 | __func__); | ||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | static void | ||
778 | l1oip_socket_close(struct l1oip *hc) | ||
779 | { | ||
780 | /* kill thread */ | ||
781 | if (hc->socket_thread) { | ||
782 | if (debug & DEBUG_L1OIP_SOCKET) | ||
783 | printk(KERN_DEBUG "%s: socket thread exists, " | ||
784 | "killing...\n", __func__); | ||
785 | send_sig(SIGTERM, hc->socket_thread, 0); | ||
786 | wait_for_completion(&hc->socket_complete); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | static int | ||
791 | l1oip_socket_open(struct l1oip *hc) | ||
792 | { | ||
793 | /* in case of reopen, we need to close first */ | ||
794 | l1oip_socket_close(hc); | ||
795 | |||
796 | init_completion(&hc->socket_complete); | ||
797 | |||
798 | /* create receive process */ | ||
799 | hc->socket_thread = kthread_run(l1oip_socket_thread, hc, "l1oip_%s", | ||
800 | hc->name); | ||
801 | if (IS_ERR(hc->socket_thread)) { | ||
802 | int err = PTR_ERR(hc->socket_thread); | ||
803 | printk(KERN_ERR "%s: Failed (%d) to create socket process.\n", | ||
804 | __func__, err); | ||
805 | hc->socket_thread = NULL; | ||
806 | sock_release(hc->socket); | ||
807 | return err; | ||
808 | } | ||
809 | if (debug & DEBUG_L1OIP_SOCKET) | ||
810 | printk(KERN_DEBUG "%s: socket thread created\n", __func__); | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | |||
816 | static void | ||
817 | l1oip_send_bh(struct work_struct *work) | ||
818 | { | ||
819 | struct l1oip *hc = container_of(work, struct l1oip, workq); | ||
820 | |||
821 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
822 | printk(KERN_DEBUG "%s: keepalive timer expired, sending empty " | ||
823 | "frame on dchannel\n", __func__); | ||
824 | |||
825 | /* send an empty l1oip frame at D-channel */ | ||
826 | l1oip_socket_send(hc, 0, hc->d_idx, 0, 0, NULL, 0); | ||
827 | } | ||
828 | |||
829 | |||
830 | /* | ||
831 | * timer stuff | ||
832 | */ | ||
833 | static void | ||
834 | l1oip_keepalive(void *data) | ||
835 | { | ||
836 | struct l1oip *hc = (struct l1oip *)data; | ||
837 | |||
838 | schedule_work(&hc->workq); | ||
839 | } | ||
840 | |||
841 | static void | ||
842 | l1oip_timeout(void *data) | ||
843 | { | ||
844 | struct l1oip *hc = (struct l1oip *)data; | ||
845 | struct dchannel *dch = hc->chan[hc->d_idx].dch; | ||
846 | |||
847 | if (debug & DEBUG_L1OIP_MSG) | ||
848 | printk(KERN_DEBUG "%s: timeout timer expired, turn layer one " | ||
849 | "down.\n", __func__); | ||
850 | |||
851 | hc->timeout_on = 0; /* state that timer must be initialized next time */ | ||
852 | |||
853 | /* if timeout, we send up a PH_DEACTIVATE and deactivate */ | ||
854 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
855 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
856 | printk(KERN_DEBUG "%s: interface become deactivated " | ||
857 | "due to timeout\n", __func__); | ||
858 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
859 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
860 | NULL, GFP_ATOMIC); | ||
861 | } | ||
862 | |||
863 | /* if we have ondemand set, we remove ip address */ | ||
864 | if (hc->ondemand) { | ||
865 | if (debug & DEBUG_L1OIP_MSG) | ||
866 | printk(KERN_DEBUG "%s: on demand causes ip address to " | ||
867 | "be removed\n", __func__); | ||
868 | hc->sin_remote.sin_addr.s_addr = 0; | ||
869 | } | ||
870 | } | ||
871 | |||
872 | |||
873 | /* | ||
874 | * message handling | ||
875 | */ | ||
876 | static int | ||
877 | handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
878 | { | ||
879 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
880 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
881 | struct l1oip *hc = dch->hw; | ||
882 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
883 | int ret = -EINVAL; | ||
884 | int l, ll; | ||
885 | unsigned char *p; | ||
886 | |||
887 | switch (hh->prim) { | ||
888 | case PH_DATA_REQ: | ||
889 | if (skb->len < 1) { | ||
890 | printk(KERN_WARNING "%s: skb too small\n", | ||
891 | __func__); | ||
892 | break; | ||
893 | } | ||
894 | if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { | ||
895 | printk(KERN_WARNING "%s: skb too large\n", | ||
896 | __func__); | ||
897 | break; | ||
898 | } | ||
899 | /* send frame */ | ||
900 | p = skb->data; | ||
901 | l = skb->len; | ||
902 | while (l) { | ||
903 | ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; | ||
904 | l1oip_socket_send(hc, 0, dch->slot, 0, | ||
905 | hc->chan[dch->slot].tx_counter++, p, ll); | ||
906 | p += ll; | ||
907 | l -= ll; | ||
908 | } | ||
909 | skb_trim(skb, 0); | ||
910 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
911 | return 0; | ||
912 | case PH_ACTIVATE_REQ: | ||
913 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
914 | printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" | ||
915 | , __func__, dch->slot, hc->b_num+1); | ||
916 | skb_trim(skb, 0); | ||
917 | if (test_bit(FLG_ACTIVE, &dch->Flags)) | ||
918 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
919 | else | ||
920 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
921 | return 0; | ||
922 | case PH_DEACTIVATE_REQ: | ||
923 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
924 | printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " | ||
925 | "(1..%d)\n", __func__, dch->slot, | ||
926 | hc->b_num+1); | ||
927 | skb_trim(skb, 0); | ||
928 | if (test_bit(FLG_ACTIVE, &dch->Flags)) | ||
929 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
930 | else | ||
931 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
932 | return 0; | ||
933 | } | ||
934 | if (!ret) | ||
935 | dev_kfree_skb(skb); | ||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static int | ||
940 | channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) | ||
941 | { | ||
942 | int ret = 0; | ||
943 | struct l1oip *hc = dch->hw; | ||
944 | |||
945 | switch (cq->op) { | ||
946 | case MISDN_CTRL_GETOP: | ||
947 | cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER; | ||
948 | break; | ||
949 | case MISDN_CTRL_SETPEER: | ||
950 | hc->remoteip = (u32)cq->p1; | ||
951 | hc->remoteport = cq->p2 & 0xffff; | ||
952 | hc->localport = cq->p2 >> 16; | ||
953 | if (!hc->remoteport) | ||
954 | hc->remoteport = hc->localport; | ||
955 | if (debug & DEBUG_L1OIP_SOCKET) | ||
956 | printk(KERN_DEBUG "%s: got new ip address from user " | ||
957 | "space.\n", __func__); | ||
958 | l1oip_socket_open(hc); | ||
959 | break; | ||
960 | case MISDN_CTRL_UNSETPEER: | ||
961 | if (debug & DEBUG_L1OIP_SOCKET) | ||
962 | printk(KERN_DEBUG "%s: removing ip address.\n", | ||
963 | __func__); | ||
964 | hc->remoteip = 0; | ||
965 | l1oip_socket_open(hc); | ||
966 | break; | ||
967 | default: | ||
968 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
969 | __func__, cq->op); | ||
970 | ret = -EINVAL; | ||
971 | break; | ||
972 | } | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | static int | ||
977 | open_dchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) | ||
978 | { | ||
979 | if (debug & DEBUG_HW_OPEN) | ||
980 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
981 | dch->dev.id, __builtin_return_address(0)); | ||
982 | if (rq->protocol == ISDN_P_NONE) | ||
983 | return -EINVAL; | ||
984 | if ((dch->dev.D.protocol != ISDN_P_NONE) && | ||
985 | (dch->dev.D.protocol != rq->protocol)) { | ||
986 | if (debug & DEBUG_HW_OPEN) | ||
987 | printk(KERN_WARNING "%s: change protocol %x to %x\n", | ||
988 | __func__, dch->dev.D.protocol, rq->protocol); | ||
989 | } | ||
990 | if (dch->dev.D.protocol != rq->protocol) | ||
991 | dch->dev.D.protocol = rq->protocol; | ||
992 | |||
993 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
994 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
995 | 0, NULL, GFP_KERNEL); | ||
996 | } | ||
997 | rq->ch = &dch->dev.D; | ||
998 | if (!try_module_get(THIS_MODULE)) | ||
999 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
1003 | static int | ||
1004 | open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) | ||
1005 | { | ||
1006 | struct bchannel *bch; | ||
1007 | int ch; | ||
1008 | |||
1009 | if (!test_bit(rq->adr.channel & 0x1f, | ||
1010 | &dch->dev.channelmap[rq->adr.channel >> 5])) | ||
1011 | return -EINVAL; | ||
1012 | if (rq->protocol == ISDN_P_NONE) | ||
1013 | return -EINVAL; | ||
1014 | ch = rq->adr.channel; /* BRI: 1=B1 2=B2 PRI: 1..15,17.. */ | ||
1015 | bch = hc->chan[ch].bch; | ||
1016 | if (!bch) { | ||
1017 | printk(KERN_ERR "%s:internal error ch %d has no bch\n", | ||
1018 | __func__, ch); | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
1022 | return -EBUSY; /* b-channel can be only open once */ | ||
1023 | bch->ch.protocol = rq->protocol; | ||
1024 | rq->ch = &bch->ch; | ||
1025 | if (!try_module_get(THIS_MODULE)) | ||
1026 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | static int | ||
1031 | l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1032 | { | ||
1033 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
1034 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
1035 | struct l1oip *hc = dch->hw; | ||
1036 | struct channel_req *rq; | ||
1037 | int err = 0; | ||
1038 | |||
1039 | if (dch->debug & DEBUG_HW) | ||
1040 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
1041 | __func__, cmd, arg); | ||
1042 | switch (cmd) { | ||
1043 | case OPEN_CHANNEL: | ||
1044 | rq = arg; | ||
1045 | switch (rq->protocol) { | ||
1046 | case ISDN_P_TE_S0: | ||
1047 | case ISDN_P_NT_S0: | ||
1048 | if (hc->pri) { | ||
1049 | err = -EINVAL; | ||
1050 | break; | ||
1051 | } | ||
1052 | err = open_dchannel(hc, dch, rq); | ||
1053 | break; | ||
1054 | case ISDN_P_TE_E1: | ||
1055 | case ISDN_P_NT_E1: | ||
1056 | if (!hc->pri) { | ||
1057 | err = -EINVAL; | ||
1058 | break; | ||
1059 | } | ||
1060 | err = open_dchannel(hc, dch, rq); | ||
1061 | break; | ||
1062 | default: | ||
1063 | err = open_bchannel(hc, dch, rq); | ||
1064 | } | ||
1065 | break; | ||
1066 | case CLOSE_CHANNEL: | ||
1067 | if (debug & DEBUG_HW_OPEN) | ||
1068 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
1069 | __func__, dch->dev.id, | ||
1070 | __builtin_return_address(0)); | ||
1071 | module_put(THIS_MODULE); | ||
1072 | break; | ||
1073 | case CONTROL_CHANNEL: | ||
1074 | err = channel_dctrl(dch, arg); | ||
1075 | break; | ||
1076 | default: | ||
1077 | if (dch->debug & DEBUG_HW) | ||
1078 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
1079 | __func__, cmd); | ||
1080 | err = -EINVAL; | ||
1081 | } | ||
1082 | return err; | ||
1083 | } | ||
1084 | |||
1085 | static int | ||
1086 | handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1087 | { | ||
1088 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1089 | struct l1oip *hc = bch->hw; | ||
1090 | int ret = -EINVAL; | ||
1091 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1092 | int l, ll, i; | ||
1093 | unsigned char *p; | ||
1094 | |||
1095 | switch (hh->prim) { | ||
1096 | case PH_DATA_REQ: | ||
1097 | if (skb->len <= 0) { | ||
1098 | printk(KERN_WARNING "%s: skb too small\n", | ||
1099 | __func__); | ||
1100 | break; | ||
1101 | } | ||
1102 | if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { | ||
1103 | printk(KERN_WARNING "%s: skb too large\n", | ||
1104 | __func__); | ||
1105 | break; | ||
1106 | } | ||
1107 | /* check for AIS / ulaw-silence */ | ||
1108 | p = skb->data; | ||
1109 | l = skb->len; | ||
1110 | for (i = 0; i < l; i++) { | ||
1111 | if (*p++ != 0xff) | ||
1112 | break; | ||
1113 | } | ||
1114 | if (i == l) { | ||
1115 | if (debug & DEBUG_L1OIP_MSG) | ||
1116 | printk(KERN_DEBUG "%s: got AIS, not sending, " | ||
1117 | "but counting\n", __func__); | ||
1118 | hc->chan[bch->slot].tx_counter += l; | ||
1119 | skb_trim(skb, 0); | ||
1120 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
1121 | return 0; | ||
1122 | } | ||
1123 | /* check for silence */ | ||
1124 | p = skb->data; | ||
1125 | l = skb->len; | ||
1126 | for (i = 0; i < l; i++) { | ||
1127 | if (*p++ != 0x2a) | ||
1128 | break; | ||
1129 | } | ||
1130 | if (i == l) { | ||
1131 | if (debug & DEBUG_L1OIP_MSG) | ||
1132 | printk(KERN_DEBUG "%s: got silence, not sending" | ||
1133 | ", but counting\n", __func__); | ||
1134 | hc->chan[bch->slot].tx_counter += l; | ||
1135 | skb_trim(skb, 0); | ||
1136 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | /* send frame */ | ||
1141 | p = skb->data; | ||
1142 | l = skb->len; | ||
1143 | while (l) { | ||
1144 | ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; | ||
1145 | l1oip_socket_send(hc, hc->codec, bch->slot, 0, | ||
1146 | hc->chan[bch->slot].tx_counter, p, ll); | ||
1147 | hc->chan[bch->slot].tx_counter += ll; | ||
1148 | p += ll; | ||
1149 | l -= ll; | ||
1150 | } | ||
1151 | skb_trim(skb, 0); | ||
1152 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
1153 | return 0; | ||
1154 | case PH_ACTIVATE_REQ: | ||
1155 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
1156 | printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" | ||
1157 | , __func__, bch->slot, hc->b_num+1); | ||
1158 | hc->chan[bch->slot].codecstate = 0; | ||
1159 | test_and_set_bit(FLG_ACTIVE, &bch->Flags); | ||
1160 | skb_trim(skb, 0); | ||
1161 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
1162 | return 0; | ||
1163 | case PH_DEACTIVATE_REQ: | ||
1164 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
1165 | printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " | ||
1166 | "(1..%d)\n", __func__, bch->slot, | ||
1167 | hc->b_num+1); | ||
1168 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1169 | skb_trim(skb, 0); | ||
1170 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
1171 | return 0; | ||
1172 | } | ||
1173 | if (!ret) | ||
1174 | dev_kfree_skb(skb); | ||
1175 | return ret; | ||
1176 | } | ||
1177 | |||
1178 | static int | ||
1179 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
1180 | { | ||
1181 | int ret = 0; | ||
1182 | struct dsp_features *features = | ||
1183 | (struct dsp_features *)(*((u_long *)&cq->p1)); | ||
1184 | |||
1185 | switch (cq->op) { | ||
1186 | case MISDN_CTRL_GETOP: | ||
1187 | cq->op = MISDN_CTRL_HW_FEATURES_OP; | ||
1188 | break; | ||
1189 | case MISDN_CTRL_HW_FEATURES: /* fill features structure */ | ||
1190 | if (debug & DEBUG_L1OIP_MSG) | ||
1191 | printk(KERN_DEBUG "%s: HW_FEATURE request\n", | ||
1192 | __func__); | ||
1193 | /* create confirm */ | ||
1194 | features->unclocked = 1; | ||
1195 | features->unordered = 1; | ||
1196 | break; | ||
1197 | default: | ||
1198 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
1199 | __func__, cq->op); | ||
1200 | ret = -EINVAL; | ||
1201 | break; | ||
1202 | } | ||
1203 | return ret; | ||
1204 | } | ||
1205 | |||
1206 | static int | ||
1207 | l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1208 | { | ||
1209 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
1210 | int err = -EINVAL; | ||
1211 | |||
1212 | if (bch->debug & DEBUG_HW) | ||
1213 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
1214 | __func__, cmd, arg); | ||
1215 | switch (cmd) { | ||
1216 | case CLOSE_CHANNEL: | ||
1217 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
1218 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
1219 | ch->protocol = ISDN_P_NONE; | ||
1220 | ch->peer = NULL; | ||
1221 | module_put(THIS_MODULE); | ||
1222 | err = 0; | ||
1223 | break; | ||
1224 | case CONTROL_CHANNEL: | ||
1225 | err = channel_bctrl(bch, arg); | ||
1226 | break; | ||
1227 | default: | ||
1228 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
1229 | __func__, cmd); | ||
1230 | } | ||
1231 | return err; | ||
1232 | } | ||
1233 | |||
1234 | |||
1235 | /* | ||
1236 | * cleanup module and stack | ||
1237 | */ | ||
1238 | static void | ||
1239 | release_card(struct l1oip *hc) | ||
1240 | { | ||
1241 | int ch; | ||
1242 | |||
1243 | if (timer_pending(&hc->keep_tl)) | ||
1244 | del_timer(&hc->keep_tl); | ||
1245 | |||
1246 | if (timer_pending(&hc->timeout_tl)) | ||
1247 | del_timer(&hc->timeout_tl); | ||
1248 | |||
1249 | if (hc->socket_thread) | ||
1250 | l1oip_socket_close(hc); | ||
1251 | |||
1252 | if (hc->registered && hc->chan[hc->d_idx].dch) | ||
1253 | mISDN_unregister_device(&hc->chan[hc->d_idx].dch->dev); | ||
1254 | for (ch = 0; ch < 128; ch++) { | ||
1255 | if (hc->chan[ch].dch) { | ||
1256 | mISDN_freedchannel(hc->chan[ch].dch); | ||
1257 | kfree(hc->chan[ch].dch); | ||
1258 | } | ||
1259 | if (hc->chan[ch].bch) { | ||
1260 | mISDN_freebchannel(hc->chan[ch].bch); | ||
1261 | kfree(hc->chan[ch].bch); | ||
1262 | #ifdef REORDER_DEBUG | ||
1263 | if (hc->chan[ch].disorder_skb) | ||
1264 | dev_kfree_skb(hc->chan[ch].disorder_skb); | ||
1265 | #endif | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | spin_lock(&l1oip_lock); | ||
1270 | list_del(&hc->list); | ||
1271 | spin_unlock(&l1oip_lock); | ||
1272 | |||
1273 | kfree(hc); | ||
1274 | } | ||
1275 | |||
1276 | static void | ||
1277 | l1oip_cleanup(void) | ||
1278 | { | ||
1279 | struct l1oip *hc, *next; | ||
1280 | |||
1281 | list_for_each_entry_safe(hc, next, &l1oip_ilist, list) | ||
1282 | release_card(hc); | ||
1283 | |||
1284 | l1oip_4bit_free(); | ||
1285 | } | ||
1286 | |||
1287 | |||
1288 | /* | ||
1289 | * module and stack init | ||
1290 | */ | ||
1291 | static int | ||
1292 | init_card(struct l1oip *hc, int pri, int bundle) | ||
1293 | { | ||
1294 | struct dchannel *dch; | ||
1295 | struct bchannel *bch; | ||
1296 | int ret; | ||
1297 | int i, ch; | ||
1298 | |||
1299 | spin_lock_init(&hc->socket_lock); | ||
1300 | hc->idx = l1oip_cnt; | ||
1301 | hc->pri = pri; | ||
1302 | hc->d_idx = pri?16:3; | ||
1303 | hc->b_num = pri?30:2; | ||
1304 | hc->bundle = bundle; | ||
1305 | if (hc->pri) | ||
1306 | sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); | ||
1307 | else | ||
1308 | sprintf(hc->name, "l1oip-s0.%d", l1oip_cnt + 1); | ||
1309 | |||
1310 | switch (codec[l1oip_cnt]) { | ||
1311 | case 0: /* as is */ | ||
1312 | case 1: /* alaw */ | ||
1313 | case 2: /* ulaw */ | ||
1314 | case 3: /* 4bit */ | ||
1315 | break; | ||
1316 | default: | ||
1317 | printk(KERN_ERR "Codec(%d) not supported.\n", | ||
1318 | codec[l1oip_cnt]); | ||
1319 | return -EINVAL; | ||
1320 | } | ||
1321 | hc->codec = codec[l1oip_cnt]; | ||
1322 | if (debug & DEBUG_L1OIP_INIT) | ||
1323 | printk(KERN_DEBUG "%s: using codec %d\n", | ||
1324 | __func__, hc->codec); | ||
1325 | |||
1326 | if (id[l1oip_cnt] == 0) { | ||
1327 | printk(KERN_WARNING "Warning: No 'id' value given or " | ||
1328 | "0, this is highly unsecure. Please use 32 " | ||
1329 | "bit randmom number 0x...\n"); | ||
1330 | } | ||
1331 | hc->id = id[l1oip_cnt]; | ||
1332 | if (debug & DEBUG_L1OIP_INIT) | ||
1333 | printk(KERN_DEBUG "%s: using id 0x%x\n", __func__, hc->id); | ||
1334 | |||
1335 | hc->ondemand = ondemand[l1oip_cnt]; | ||
1336 | if (hc->ondemand && !hc->id) { | ||
1337 | printk(KERN_ERR "%s: ondemand option only allowed in " | ||
1338 | "conjunction with non 0 ID\n", __func__); | ||
1339 | return -EINVAL; | ||
1340 | } | ||
1341 | |||
1342 | if (limit[l1oip_cnt]) | ||
1343 | hc->b_num = limit[l1oip_cnt]; | ||
1344 | if (!pri && hc->b_num > 2) { | ||
1345 | printk(KERN_ERR "Maximum limit for BRI interface is 2 " | ||
1346 | "channels.\n"); | ||
1347 | return -EINVAL; | ||
1348 | } | ||
1349 | if (pri && hc->b_num > 126) { | ||
1350 | printk(KERN_ERR "Maximum limit for PRI interface is 126 " | ||
1351 | "channels.\n"); | ||
1352 | return -EINVAL; | ||
1353 | } | ||
1354 | if (pri && hc->b_num > 30) { | ||
1355 | printk(KERN_WARNING "Maximum limit for BRI interface is 30 " | ||
1356 | "channels.\n"); | ||
1357 | printk(KERN_WARNING "Your selection of %d channels must be " | ||
1358 | "supported by application.\n", hc->limit); | ||
1359 | } | ||
1360 | |||
1361 | hc->remoteip = ip[l1oip_cnt<<2] << 24 | ||
1362 | | ip[(l1oip_cnt<<2)+1] << 16 | ||
1363 | | ip[(l1oip_cnt<<2)+2] << 8 | ||
1364 | | ip[(l1oip_cnt<<2)+3]; | ||
1365 | hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT+l1oip_cnt); | ||
1366 | if (remoteport[l1oip_cnt]) | ||
1367 | hc->remoteport = remoteport[l1oip_cnt]; | ||
1368 | else | ||
1369 | hc->remoteport = hc->localport; | ||
1370 | if (debug & DEBUG_L1OIP_INIT) | ||
1371 | printk(KERN_DEBUG "%s: using local port %d remote ip " | ||
1372 | "%d.%d.%d.%d port %d ondemand %d\n", __func__, | ||
1373 | hc->localport, hc->remoteip >> 24, | ||
1374 | (hc->remoteip >> 16) & 0xff, | ||
1375 | (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff, | ||
1376 | hc->remoteport, hc->ondemand); | ||
1377 | |||
1378 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
1379 | if (!dch) | ||
1380 | return -ENOMEM; | ||
1381 | dch->debug = debug; | ||
1382 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL); | ||
1383 | dch->hw = hc; | ||
1384 | if (pri) | ||
1385 | dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); | ||
1386 | else | ||
1387 | dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
1388 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
1389 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
1390 | dch->dev.D.send = handle_dmsg; | ||
1391 | dch->dev.D.ctrl = l1oip_dctrl; | ||
1392 | dch->dev.nrbchan = hc->b_num; | ||
1393 | dch->slot = hc->d_idx; | ||
1394 | hc->chan[hc->d_idx].dch = dch; | ||
1395 | i = 1; | ||
1396 | for (ch = 0; ch < dch->dev.nrbchan; ch++) { | ||
1397 | if (ch == 15) | ||
1398 | i++; | ||
1399 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
1400 | if (!bch) { | ||
1401 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
1402 | __func__); | ||
1403 | return -ENOMEM; | ||
1404 | } | ||
1405 | bch->nr = i + ch; | ||
1406 | bch->slot = i + ch; | ||
1407 | bch->debug = debug; | ||
1408 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
1409 | bch->hw = hc; | ||
1410 | bch->ch.send = handle_bmsg; | ||
1411 | bch->ch.ctrl = l1oip_bctrl; | ||
1412 | bch->ch.nr = i + ch; | ||
1413 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
1414 | hc->chan[i + ch].bch = bch; | ||
1415 | test_and_set_bit(bch->nr & 0x1f, | ||
1416 | &dch->dev.channelmap[bch->nr >> 5]); | ||
1417 | } | ||
1418 | ret = mISDN_register_device(&dch->dev, hc->name); | ||
1419 | if (ret) | ||
1420 | return ret; | ||
1421 | hc->registered = 1; | ||
1422 | |||
1423 | if (debug & DEBUG_L1OIP_INIT) | ||
1424 | printk(KERN_DEBUG "%s: Setting up network card(%d)\n", | ||
1425 | __func__, l1oip_cnt + 1); | ||
1426 | ret = l1oip_socket_open(hc); | ||
1427 | if (ret) | ||
1428 | return ret; | ||
1429 | |||
1430 | hc->keep_tl.function = (void *)l1oip_keepalive; | ||
1431 | hc->keep_tl.data = (ulong)hc; | ||
1432 | init_timer(&hc->keep_tl); | ||
1433 | hc->keep_tl.expires = jiffies + 2*HZ; /* two seconds first time */ | ||
1434 | add_timer(&hc->keep_tl); | ||
1435 | |||
1436 | hc->timeout_tl.function = (void *)l1oip_timeout; | ||
1437 | hc->timeout_tl.data = (ulong)hc; | ||
1438 | init_timer(&hc->timeout_tl); | ||
1439 | hc->timeout_on = 0; /* state that we have timer off */ | ||
1440 | |||
1441 | return 0; | ||
1442 | } | ||
1443 | |||
1444 | static int __init | ||
1445 | l1oip_init(void) | ||
1446 | { | ||
1447 | int pri, bundle; | ||
1448 | struct l1oip *hc; | ||
1449 | int ret; | ||
1450 | |||
1451 | printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n", | ||
1452 | l1oip_revision); | ||
1453 | |||
1454 | INIT_LIST_HEAD(&l1oip_ilist); | ||
1455 | spin_lock_init(&l1oip_lock); | ||
1456 | |||
1457 | if (l1oip_4bit_alloc(ulaw)) | ||
1458 | return -ENOMEM; | ||
1459 | |||
1460 | l1oip_cnt = 0; | ||
1461 | while (type[l1oip_cnt] && l1oip_cnt < MAX_CARDS) { | ||
1462 | switch (type[l1oip_cnt] & 0xff) { | ||
1463 | case 1: | ||
1464 | pri = 0; | ||
1465 | bundle = 0; | ||
1466 | break; | ||
1467 | case 2: | ||
1468 | pri = 1; | ||
1469 | bundle = 0; | ||
1470 | break; | ||
1471 | case 3: | ||
1472 | pri = 0; | ||
1473 | bundle = 1; | ||
1474 | break; | ||
1475 | case 4: | ||
1476 | pri = 1; | ||
1477 | bundle = 1; | ||
1478 | break; | ||
1479 | default: | ||
1480 | printk(KERN_ERR "Card type(%d) not supported.\n", | ||
1481 | type[l1oip_cnt] & 0xff); | ||
1482 | l1oip_cleanup(); | ||
1483 | return -EINVAL; | ||
1484 | } | ||
1485 | |||
1486 | if (debug & DEBUG_L1OIP_INIT) | ||
1487 | printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", | ||
1488 | __func__, l1oip_cnt, pri?"PRI":"BRI", | ||
1489 | bundle?"bundled IP packet for all B-channels" | ||
1490 | :"seperate IP packets for every B-channel"); | ||
1491 | |||
1492 | hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC); | ||
1493 | if (!hc) { | ||
1494 | printk(KERN_ERR "No kmem for L1-over-IP driver.\n"); | ||
1495 | l1oip_cleanup(); | ||
1496 | return -ENOMEM; | ||
1497 | } | ||
1498 | INIT_WORK(&hc->workq, (void *)l1oip_send_bh); | ||
1499 | |||
1500 | spin_lock(&l1oip_lock); | ||
1501 | list_add_tail(&hc->list, &l1oip_ilist); | ||
1502 | spin_unlock(&l1oip_lock); | ||
1503 | |||
1504 | ret = init_card(hc, pri, bundle); | ||
1505 | if (ret) { | ||
1506 | l1oip_cleanup(); | ||
1507 | return ret; | ||
1508 | } | ||
1509 | |||
1510 | l1oip_cnt++; | ||
1511 | } | ||
1512 | printk(KERN_INFO "%d virtual devices registered\n", l1oip_cnt); | ||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | module_init(l1oip_init); | ||
1517 | module_exit(l1oip_cleanup); | ||
1518 | |||
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c new file mode 100644 index 000000000000..fced1a2755f8 --- /dev/null +++ b/drivers/isdn/mISDN/layer1.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/mISDNhw.h> | ||
21 | #include "layer1.h" | ||
22 | #include "fsm.h" | ||
23 | |||
24 | static int *debug; | ||
25 | |||
26 | struct layer1 { | ||
27 | u_long Flags; | ||
28 | struct FsmInst l1m; | ||
29 | struct FsmTimer timer; | ||
30 | int delay; | ||
31 | struct dchannel *dch; | ||
32 | dchannel_l1callback *dcb; | ||
33 | }; | ||
34 | |||
35 | #define TIMER3_VALUE 7000 | ||
36 | |||
37 | static | ||
38 | struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; | ||
39 | |||
40 | enum { | ||
41 | ST_L1_F2, | ||
42 | ST_L1_F3, | ||
43 | ST_L1_F4, | ||
44 | ST_L1_F5, | ||
45 | ST_L1_F6, | ||
46 | ST_L1_F7, | ||
47 | ST_L1_F8, | ||
48 | }; | ||
49 | |||
50 | #define L1S_STATE_COUNT (ST_L1_F8+1) | ||
51 | |||
52 | static char *strL1SState[] = | ||
53 | { | ||
54 | "ST_L1_F2", | ||
55 | "ST_L1_F3", | ||
56 | "ST_L1_F4", | ||
57 | "ST_L1_F5", | ||
58 | "ST_L1_F6", | ||
59 | "ST_L1_F7", | ||
60 | "ST_L1_F8", | ||
61 | }; | ||
62 | |||
63 | enum { | ||
64 | EV_PH_ACTIVATE, | ||
65 | EV_PH_DEACTIVATE, | ||
66 | EV_RESET_IND, | ||
67 | EV_DEACT_CNF, | ||
68 | EV_DEACT_IND, | ||
69 | EV_POWER_UP, | ||
70 | EV_ANYSIG_IND, | ||
71 | EV_INFO2_IND, | ||
72 | EV_INFO4_IND, | ||
73 | EV_TIMER_DEACT, | ||
74 | EV_TIMER_ACT, | ||
75 | EV_TIMER3, | ||
76 | }; | ||
77 | |||
78 | #define L1_EVENT_COUNT (EV_TIMER3 + 1) | ||
79 | |||
80 | static char *strL1Event[] = | ||
81 | { | ||
82 | "EV_PH_ACTIVATE", | ||
83 | "EV_PH_DEACTIVATE", | ||
84 | "EV_RESET_IND", | ||
85 | "EV_DEACT_CNF", | ||
86 | "EV_DEACT_IND", | ||
87 | "EV_POWER_UP", | ||
88 | "EV_ANYSIG_IND", | ||
89 | "EV_INFO2_IND", | ||
90 | "EV_INFO4_IND", | ||
91 | "EV_TIMER_DEACT", | ||
92 | "EV_TIMER_ACT", | ||
93 | "EV_TIMER3", | ||
94 | }; | ||
95 | |||
96 | static void | ||
97 | l1m_debug(struct FsmInst *fi, char *fmt, ...) | ||
98 | { | ||
99 | struct layer1 *l1 = fi->userdata; | ||
100 | va_list va; | ||
101 | |||
102 | va_start(va, fmt); | ||
103 | printk(KERN_DEBUG "%s: ", l1->dch->dev.name); | ||
104 | vprintk(fmt, va); | ||
105 | printk("\n"); | ||
106 | va_end(va); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | l1_reset(struct FsmInst *fi, int event, void *arg) | ||
111 | { | ||
112 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
113 | } | ||
114 | |||
115 | static void | ||
116 | l1_deact_cnf(struct FsmInst *fi, int event, void *arg) | ||
117 | { | ||
118 | struct layer1 *l1 = fi->userdata; | ||
119 | |||
120 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
121 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) | ||
122 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | l1_deact_req_s(struct FsmInst *fi, int event, void *arg) | ||
127 | { | ||
128 | struct layer1 *l1 = fi->userdata; | ||
129 | |||
130 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
131 | mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); | ||
132 | test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
133 | } | ||
134 | |||
135 | static void | ||
136 | l1_power_up_s(struct FsmInst *fi, int event, void *arg) | ||
137 | { | ||
138 | struct layer1 *l1 = fi->userdata; | ||
139 | |||
140 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
141 | mISDN_FsmChangeState(fi, ST_L1_F4); | ||
142 | l1->dcb(l1->dch, INFO3_P8); | ||
143 | } else | ||
144 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
145 | } | ||
146 | |||
147 | static void | ||
148 | l1_go_F5(struct FsmInst *fi, int event, void *arg) | ||
149 | { | ||
150 | mISDN_FsmChangeState(fi, ST_L1_F5); | ||
151 | } | ||
152 | |||
153 | static void | ||
154 | l1_go_F8(struct FsmInst *fi, int event, void *arg) | ||
155 | { | ||
156 | mISDN_FsmChangeState(fi, ST_L1_F8); | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | l1_info2_ind(struct FsmInst *fi, int event, void *arg) | ||
161 | { | ||
162 | struct layer1 *l1 = fi->userdata; | ||
163 | |||
164 | mISDN_FsmChangeState(fi, ST_L1_F6); | ||
165 | l1->dcb(l1->dch, INFO3_P8); | ||
166 | } | ||
167 | |||
168 | static void | ||
169 | l1_info4_ind(struct FsmInst *fi, int event, void *arg) | ||
170 | { | ||
171 | struct layer1 *l1 = fi->userdata; | ||
172 | |||
173 | mISDN_FsmChangeState(fi, ST_L1_F7); | ||
174 | l1->dcb(l1->dch, INFO3_P8); | ||
175 | if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) | ||
176 | mISDN_FsmDelTimer(&l1->timer, 4); | ||
177 | if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { | ||
178 | if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) | ||
179 | mISDN_FsmDelTimer(&l1->timer, 3); | ||
180 | mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); | ||
181 | test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void | ||
186 | l1_timer3(struct FsmInst *fi, int event, void *arg) | ||
187 | { | ||
188 | struct layer1 *l1 = fi->userdata; | ||
189 | |||
190 | test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags); | ||
191 | if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
192 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
193 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
194 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
195 | } | ||
196 | if (l1->l1m.state != ST_L1_F6) { | ||
197 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
198 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void | ||
203 | l1_timer_act(struct FsmInst *fi, int event, void *arg) | ||
204 | { | ||
205 | struct layer1 *l1 = fi->userdata; | ||
206 | |||
207 | test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
208 | test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
209 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
210 | } | ||
211 | |||
212 | static void | ||
213 | l1_timer_deact(struct FsmInst *fi, int event, void *arg) | ||
214 | { | ||
215 | struct layer1 *l1 = fi->userdata; | ||
216 | |||
217 | test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
218 | test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
219 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
220 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
221 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
222 | l1->dcb(l1->dch, HW_DEACT_REQ); | ||
223 | } | ||
224 | |||
225 | static void | ||
226 | l1_activate_s(struct FsmInst *fi, int event, void *arg) | ||
227 | { | ||
228 | struct layer1 *l1 = fi->userdata; | ||
229 | |||
230 | mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); | ||
231 | test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); | ||
232 | l1->dcb(l1->dch, HW_RESET_REQ); | ||
233 | } | ||
234 | |||
235 | static void | ||
236 | l1_activate_no(struct FsmInst *fi, int event, void *arg) | ||
237 | { | ||
238 | struct layer1 *l1 = fi->userdata; | ||
239 | |||
240 | if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) && | ||
241 | (!test_bit(FLG_L1_T3RUN, &l1->Flags))) { | ||
242 | test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
243 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
244 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
245 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static struct FsmNode L1SFnList[] = | ||
250 | { | ||
251 | {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, | ||
252 | {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, | ||
253 | {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, | ||
254 | {ST_L1_F3, EV_RESET_IND, l1_reset}, | ||
255 | {ST_L1_F4, EV_RESET_IND, l1_reset}, | ||
256 | {ST_L1_F5, EV_RESET_IND, l1_reset}, | ||
257 | {ST_L1_F6, EV_RESET_IND, l1_reset}, | ||
258 | {ST_L1_F7, EV_RESET_IND, l1_reset}, | ||
259 | {ST_L1_F8, EV_RESET_IND, l1_reset}, | ||
260 | {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, | ||
261 | {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, | ||
262 | {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, | ||
263 | {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, | ||
264 | {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, | ||
265 | {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, | ||
266 | {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, | ||
267 | {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, | ||
268 | {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, | ||
269 | {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, | ||
270 | {ST_L1_F4, EV_ANYSIG_IND, l1_go_F5}, | ||
271 | {ST_L1_F6, EV_ANYSIG_IND, l1_go_F8}, | ||
272 | {ST_L1_F7, EV_ANYSIG_IND, l1_go_F8}, | ||
273 | {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, | ||
274 | {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, | ||
275 | {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, | ||
276 | {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, | ||
277 | {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, | ||
278 | {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, | ||
279 | {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, | ||
280 | {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, | ||
281 | {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, | ||
282 | {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, | ||
283 | {ST_L1_F3, EV_TIMER3, l1_timer3}, | ||
284 | {ST_L1_F4, EV_TIMER3, l1_timer3}, | ||
285 | {ST_L1_F5, EV_TIMER3, l1_timer3}, | ||
286 | {ST_L1_F6, EV_TIMER3, l1_timer3}, | ||
287 | {ST_L1_F8, EV_TIMER3, l1_timer3}, | ||
288 | {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, | ||
289 | {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, | ||
290 | {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, | ||
291 | {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, | ||
292 | {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, | ||
293 | {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, | ||
294 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, | ||
295 | }; | ||
296 | |||
297 | static void | ||
298 | release_l1(struct layer1 *l1) { | ||
299 | mISDN_FsmDelTimer(&l1->timer, 0); | ||
300 | if (l1->dch) | ||
301 | l1->dch->l1 = NULL; | ||
302 | module_put(THIS_MODULE); | ||
303 | kfree(l1); | ||
304 | } | ||
305 | |||
306 | int | ||
307 | l1_event(struct layer1 *l1, u_int event) | ||
308 | { | ||
309 | int err = 0; | ||
310 | |||
311 | if (!l1) | ||
312 | return -EINVAL; | ||
313 | switch (event) { | ||
314 | case HW_RESET_IND: | ||
315 | mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL); | ||
316 | break; | ||
317 | case HW_DEACT_IND: | ||
318 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL); | ||
319 | break; | ||
320 | case HW_POWERUP_IND: | ||
321 | mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL); | ||
322 | break; | ||
323 | case HW_DEACT_CNF: | ||
324 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL); | ||
325 | break; | ||
326 | case ANYSIGNAL: | ||
327 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
328 | break; | ||
329 | case LOSTFRAMING: | ||
330 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
331 | break; | ||
332 | case INFO2: | ||
333 | mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL); | ||
334 | break; | ||
335 | case INFO4_P8: | ||
336 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
337 | break; | ||
338 | case INFO4_P10: | ||
339 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
340 | break; | ||
341 | case PH_ACTIVATE_REQ: | ||
342 | if (test_bit(FLG_L1_ACTIVATED, &l1->Flags)) | ||
343 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
344 | else { | ||
345 | test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
346 | mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL); | ||
347 | } | ||
348 | break; | ||
349 | case CLOSE_CHANNEL: | ||
350 | release_l1(l1); | ||
351 | break; | ||
352 | default: | ||
353 | if (*debug & DEBUG_L1) | ||
354 | printk(KERN_DEBUG "%s %x unhandled\n", | ||
355 | __func__, event); | ||
356 | err = -EINVAL; | ||
357 | } | ||
358 | return err; | ||
359 | } | ||
360 | EXPORT_SYMBOL(l1_event); | ||
361 | |||
362 | int | ||
363 | create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { | ||
364 | struct layer1 *nl1; | ||
365 | |||
366 | nl1 = kzalloc(sizeof(struct layer1), GFP_ATOMIC); | ||
367 | if (!nl1) { | ||
368 | printk(KERN_ERR "kmalloc struct layer1 failed\n"); | ||
369 | return -ENOMEM; | ||
370 | } | ||
371 | nl1->l1m.fsm = &l1fsm_s; | ||
372 | nl1->l1m.state = ST_L1_F3; | ||
373 | nl1->Flags = 0; | ||
374 | nl1->l1m.debug = *debug & DEBUG_L1_FSM; | ||
375 | nl1->l1m.userdata = nl1; | ||
376 | nl1->l1m.userint = 0; | ||
377 | nl1->l1m.printdebug = l1m_debug; | ||
378 | nl1->dch = dch; | ||
379 | nl1->dcb = dcb; | ||
380 | mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); | ||
381 | __module_get(THIS_MODULE); | ||
382 | dch->l1 = nl1; | ||
383 | return 0; | ||
384 | } | ||
385 | EXPORT_SYMBOL(create_l1); | ||
386 | |||
387 | int | ||
388 | l1_init(u_int *deb) | ||
389 | { | ||
390 | debug = deb; | ||
391 | l1fsm_s.state_count = L1S_STATE_COUNT; | ||
392 | l1fsm_s.event_count = L1_EVENT_COUNT; | ||
393 | l1fsm_s.strEvent = strL1Event; | ||
394 | l1fsm_s.strState = strL1SState; | ||
395 | mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | void | ||
400 | l1_cleanup(void) | ||
401 | { | ||
402 | mISDN_FsmFree(&l1fsm_s); | ||
403 | } | ||
diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h new file mode 100644 index 000000000000..9c8125fd89af --- /dev/null +++ b/drivers/isdn/mISDN/layer1.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Layer 1 defines | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #define FLG_L1_ACTIVATING 1 | ||
19 | #define FLG_L1_ACTIVATED 2 | ||
20 | #define FLG_L1_DEACTTIMER 3 | ||
21 | #define FLG_L1_ACTTIMER 4 | ||
22 | #define FLG_L1_T3RUN 5 | ||
23 | #define FLG_L1_PULL_REQ 6 | ||
24 | #define FLG_L1_UINT 7 | ||
25 | #define FLG_L1_DBLOCKED 8 | ||
26 | |||
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c new file mode 100644 index 000000000000..f5ad888ee71e --- /dev/null +++ b/drivers/isdn/mISDN/layer2.c | |||
@@ -0,0 +1,2216 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "fsm.h" | ||
19 | #include "layer2.h" | ||
20 | |||
21 | static int *debug; | ||
22 | |||
23 | static | ||
24 | struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; | ||
25 | |||
26 | static char *strL2State[] = | ||
27 | { | ||
28 | "ST_L2_1", | ||
29 | "ST_L2_2", | ||
30 | "ST_L2_3", | ||
31 | "ST_L2_4", | ||
32 | "ST_L2_5", | ||
33 | "ST_L2_6", | ||
34 | "ST_L2_7", | ||
35 | "ST_L2_8", | ||
36 | }; | ||
37 | |||
38 | enum { | ||
39 | EV_L2_UI, | ||
40 | EV_L2_SABME, | ||
41 | EV_L2_DISC, | ||
42 | EV_L2_DM, | ||
43 | EV_L2_UA, | ||
44 | EV_L2_FRMR, | ||
45 | EV_L2_SUPER, | ||
46 | EV_L2_I, | ||
47 | EV_L2_DL_DATA, | ||
48 | EV_L2_ACK_PULL, | ||
49 | EV_L2_DL_UNITDATA, | ||
50 | EV_L2_DL_ESTABLISH_REQ, | ||
51 | EV_L2_DL_RELEASE_REQ, | ||
52 | EV_L2_MDL_ASSIGN, | ||
53 | EV_L2_MDL_REMOVE, | ||
54 | EV_L2_MDL_ERROR, | ||
55 | EV_L1_DEACTIVATE, | ||
56 | EV_L2_T200, | ||
57 | EV_L2_T203, | ||
58 | EV_L2_SET_OWN_BUSY, | ||
59 | EV_L2_CLEAR_OWN_BUSY, | ||
60 | EV_L2_FRAME_ERROR, | ||
61 | }; | ||
62 | |||
63 | #define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1) | ||
64 | |||
65 | static char *strL2Event[] = | ||
66 | { | ||
67 | "EV_L2_UI", | ||
68 | "EV_L2_SABME", | ||
69 | "EV_L2_DISC", | ||
70 | "EV_L2_DM", | ||
71 | "EV_L2_UA", | ||
72 | "EV_L2_FRMR", | ||
73 | "EV_L2_SUPER", | ||
74 | "EV_L2_I", | ||
75 | "EV_L2_DL_DATA", | ||
76 | "EV_L2_ACK_PULL", | ||
77 | "EV_L2_DL_UNITDATA", | ||
78 | "EV_L2_DL_ESTABLISH_REQ", | ||
79 | "EV_L2_DL_RELEASE_REQ", | ||
80 | "EV_L2_MDL_ASSIGN", | ||
81 | "EV_L2_MDL_REMOVE", | ||
82 | "EV_L2_MDL_ERROR", | ||
83 | "EV_L1_DEACTIVATE", | ||
84 | "EV_L2_T200", | ||
85 | "EV_L2_T203", | ||
86 | "EV_L2_SET_OWN_BUSY", | ||
87 | "EV_L2_CLEAR_OWN_BUSY", | ||
88 | "EV_L2_FRAME_ERROR", | ||
89 | }; | ||
90 | |||
91 | static void | ||
92 | l2m_debug(struct FsmInst *fi, char *fmt, ...) | ||
93 | { | ||
94 | struct layer2 *l2 = fi->userdata; | ||
95 | va_list va; | ||
96 | |||
97 | if (!(*debug & DEBUG_L2_FSM)) | ||
98 | return; | ||
99 | va_start(va, fmt); | ||
100 | printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); | ||
101 | vprintk(fmt, va); | ||
102 | printk("\n"); | ||
103 | va_end(va); | ||
104 | } | ||
105 | |||
106 | inline u_int | ||
107 | l2headersize(struct layer2 *l2, int ui) | ||
108 | { | ||
109 | return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + | ||
110 | (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); | ||
111 | } | ||
112 | |||
113 | inline u_int | ||
114 | l2addrsize(struct layer2 *l2) | ||
115 | { | ||
116 | return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1; | ||
117 | } | ||
118 | |||
119 | static u_int | ||
120 | l2_newid(struct layer2 *l2) | ||
121 | { | ||
122 | u_int id; | ||
123 | |||
124 | id = l2->next_id++; | ||
125 | if (id == 0x7fff) | ||
126 | l2->next_id = 1; | ||
127 | id <<= 16; | ||
128 | id |= l2->tei << 8; | ||
129 | id |= l2->sapi; | ||
130 | return id; | ||
131 | } | ||
132 | |||
133 | static void | ||
134 | l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) | ||
135 | { | ||
136 | int err; | ||
137 | |||
138 | if (!l2->up) | ||
139 | return; | ||
140 | mISDN_HEAD_PRIM(skb) = prim; | ||
141 | mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; | ||
142 | err = l2->up->send(l2->up, skb); | ||
143 | if (err) { | ||
144 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
145 | dev_kfree_skb(skb); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void | ||
150 | l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) | ||
151 | { | ||
152 | struct sk_buff *skb; | ||
153 | struct mISDNhead *hh; | ||
154 | int err; | ||
155 | |||
156 | if (!l2->up) | ||
157 | return; | ||
158 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
159 | if (!skb) | ||
160 | return; | ||
161 | hh = mISDN_HEAD_P(skb); | ||
162 | hh->prim = prim; | ||
163 | hh->id = (l2->ch.nr << 16) | l2->ch.addr; | ||
164 | if (len) | ||
165 | memcpy(skb_put(skb, len), arg, len); | ||
166 | err = l2->up->send(l2->up, skb); | ||
167 | if (err) { | ||
168 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
169 | dev_kfree_skb(skb); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static int | ||
174 | l2down_skb(struct layer2 *l2, struct sk_buff *skb) { | ||
175 | int ret; | ||
176 | |||
177 | ret = l2->ch.recv(l2->ch.peer, skb); | ||
178 | if (ret && (*debug & DEBUG_L2_RECV)) | ||
179 | printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | l2down_raw(struct layer2 *l2, struct sk_buff *skb) | ||
185 | { | ||
186 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
187 | |||
188 | if (hh->prim == PH_DATA_REQ) { | ||
189 | if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
190 | skb_queue_tail(&l2->down_queue, skb); | ||
191 | return 0; | ||
192 | } | ||
193 | l2->down_id = mISDN_HEAD_ID(skb); | ||
194 | } | ||
195 | return l2down_skb(l2, skb); | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb) | ||
200 | { | ||
201 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
202 | |||
203 | hh->prim = prim; | ||
204 | hh->id = id; | ||
205 | return l2down_raw(l2, skb); | ||
206 | } | ||
207 | |||
208 | static int | ||
209 | l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg) | ||
210 | { | ||
211 | struct sk_buff *skb; | ||
212 | int err; | ||
213 | struct mISDNhead *hh; | ||
214 | |||
215 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
216 | if (!skb) | ||
217 | return -ENOMEM; | ||
218 | hh = mISDN_HEAD_P(skb); | ||
219 | hh->prim = prim; | ||
220 | hh->id = id; | ||
221 | if (len) | ||
222 | memcpy(skb_put(skb, len), arg, len); | ||
223 | err = l2down_raw(l2, skb); | ||
224 | if (err) | ||
225 | dev_kfree_skb(skb); | ||
226 | return err; | ||
227 | } | ||
228 | |||
229 | static int | ||
230 | ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { | ||
231 | struct sk_buff *nskb = skb; | ||
232 | int ret = -EAGAIN; | ||
233 | |||
234 | if (test_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
235 | if (hh->id == l2->down_id) { | ||
236 | nskb = skb_dequeue(&l2->down_queue); | ||
237 | if (nskb) { | ||
238 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
239 | if (l2down_skb(l2, nskb)) { | ||
240 | dev_kfree_skb(nskb); | ||
241 | l2->down_id = MISDN_ID_NONE; | ||
242 | } | ||
243 | } else | ||
244 | l2->down_id = MISDN_ID_NONE; | ||
245 | if (ret) { | ||
246 | dev_kfree_skb(skb); | ||
247 | ret = 0; | ||
248 | } | ||
249 | if (l2->down_id == MISDN_ID_NONE) { | ||
250 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
251 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
256 | nskb = skb_dequeue(&l2->down_queue); | ||
257 | if (nskb) { | ||
258 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
259 | if (l2down_skb(l2, nskb)) { | ||
260 | dev_kfree_skb(nskb); | ||
261 | l2->down_id = MISDN_ID_NONE; | ||
262 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
263 | } | ||
264 | } else | ||
265 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | l2mgr(struct layer2 *l2, u_int prim, void *arg) { | ||
272 | long c = (long)arg; | ||
273 | |||
274 | printk(KERN_WARNING | ||
275 | "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); | ||
276 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
277 | !test_bit(FLG_FIXED_TEI, &l2->flag)) { | ||
278 | switch (c) { | ||
279 | case 'C': | ||
280 | case 'D': | ||
281 | case 'G': | ||
282 | case 'H': | ||
283 | l2_tei(l2, prim, (u_long)arg); | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void | ||
291 | set_peer_busy(struct layer2 *l2) { | ||
292 | test_and_set_bit(FLG_PEER_BUSY, &l2->flag); | ||
293 | if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) | ||
294 | test_and_set_bit(FLG_L2BLOCK, &l2->flag); | ||
295 | } | ||
296 | |||
297 | static void | ||
298 | clear_peer_busy(struct layer2 *l2) { | ||
299 | if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) | ||
300 | test_and_clear_bit(FLG_L2BLOCK, &l2->flag); | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | InitWin(struct layer2 *l2) | ||
305 | { | ||
306 | int i; | ||
307 | |||
308 | for (i = 0; i < MAX_WINDOW; i++) | ||
309 | l2->windowar[i] = NULL; | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | freewin(struct layer2 *l2) | ||
314 | { | ||
315 | int i, cnt = 0; | ||
316 | |||
317 | for (i = 0; i < MAX_WINDOW; i++) { | ||
318 | if (l2->windowar[i]) { | ||
319 | cnt++; | ||
320 | dev_kfree_skb(l2->windowar[i]); | ||
321 | l2->windowar[i] = NULL; | ||
322 | } | ||
323 | } | ||
324 | return cnt; | ||
325 | } | ||
326 | |||
327 | static void | ||
328 | ReleaseWin(struct layer2 *l2) | ||
329 | { | ||
330 | int cnt = freewin(l2); | ||
331 | |||
332 | if (cnt) | ||
333 | printk(KERN_WARNING | ||
334 | "isdnl2 freed %d skbuffs in release\n", cnt); | ||
335 | } | ||
336 | |||
337 | inline unsigned int | ||
338 | cansend(struct layer2 *l2) | ||
339 | { | ||
340 | unsigned int p1; | ||
341 | |||
342 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
343 | p1 = (l2->vs - l2->va) % 128; | ||
344 | else | ||
345 | p1 = (l2->vs - l2->va) % 8; | ||
346 | return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag); | ||
347 | } | ||
348 | |||
349 | inline void | ||
350 | clear_exception(struct layer2 *l2) | ||
351 | { | ||
352 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
353 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
354 | test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); | ||
355 | clear_peer_busy(l2); | ||
356 | } | ||
357 | |||
358 | static int | ||
359 | sethdraddr(struct layer2 *l2, u_char *header, int rsp) | ||
360 | { | ||
361 | u_char *ptr = header; | ||
362 | int crbit = rsp; | ||
363 | |||
364 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
365 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
366 | crbit = !crbit; | ||
367 | *ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0); | ||
368 | *ptr++ = (l2->tei << 1) | 1; | ||
369 | return 2; | ||
370 | } else { | ||
371 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
372 | crbit = !crbit; | ||
373 | if (crbit) | ||
374 | *ptr++ = l2->addr.B; | ||
375 | else | ||
376 | *ptr++ = l2->addr.A; | ||
377 | return 1; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static inline void | ||
382 | enqueue_super(struct layer2 *l2, struct sk_buff *skb) | ||
383 | { | ||
384 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
385 | dev_kfree_skb(skb); | ||
386 | } | ||
387 | |||
388 | static inline void | ||
389 | enqueue_ui(struct layer2 *l2, struct sk_buff *skb) | ||
390 | { | ||
391 | if (l2->tm) | ||
392 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
393 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
394 | dev_kfree_skb(skb); | ||
395 | } | ||
396 | |||
397 | inline int | ||
398 | IsUI(u_char *data) | ||
399 | { | ||
400 | return (data[0] & 0xef) == UI; | ||
401 | } | ||
402 | |||
403 | inline int | ||
404 | IsUA(u_char *data) | ||
405 | { | ||
406 | return (data[0] & 0xef) == UA; | ||
407 | } | ||
408 | |||
409 | inline int | ||
410 | IsDM(u_char *data) | ||
411 | { | ||
412 | return (data[0] & 0xef) == DM; | ||
413 | } | ||
414 | |||
415 | inline int | ||
416 | IsDISC(u_char *data) | ||
417 | { | ||
418 | return (data[0] & 0xef) == DISC; | ||
419 | } | ||
420 | |||
421 | inline int | ||
422 | IsRR(u_char *data, struct layer2 *l2) | ||
423 | { | ||
424 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
425 | return data[0] == RR; | ||
426 | else | ||
427 | return (data[0] & 0xf) == 1; | ||
428 | } | ||
429 | |||
430 | inline int | ||
431 | IsSFrame(u_char *data, struct layer2 *l2) | ||
432 | { | ||
433 | register u_char d = *data; | ||
434 | |||
435 | if (!test_bit(FLG_MOD128, &l2->flag)) | ||
436 | d &= 0xf; | ||
437 | return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c); | ||
438 | } | ||
439 | |||
440 | inline int | ||
441 | IsSABME(u_char *data, struct layer2 *l2) | ||
442 | { | ||
443 | u_char d = data[0] & ~0x10; | ||
444 | |||
445 | return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM; | ||
446 | } | ||
447 | |||
448 | inline int | ||
449 | IsREJ(u_char *data, struct layer2 *l2) | ||
450 | { | ||
451 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
452 | data[0] == REJ : (data[0] & 0xf) == REJ; | ||
453 | } | ||
454 | |||
455 | inline int | ||
456 | IsFRMR(u_char *data) | ||
457 | { | ||
458 | return (data[0] & 0xef) == FRMR; | ||
459 | } | ||
460 | |||
461 | inline int | ||
462 | IsRNR(u_char *data, struct layer2 *l2) | ||
463 | { | ||
464 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
465 | data[0] == RNR : (data[0] & 0xf) == RNR; | ||
466 | } | ||
467 | |||
468 | int | ||
469 | iframe_error(struct layer2 *l2, struct sk_buff *skb) | ||
470 | { | ||
471 | u_int i; | ||
472 | int rsp = *skb->data & 0x2; | ||
473 | |||
474 | i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1); | ||
475 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
476 | rsp = !rsp; | ||
477 | if (rsp) | ||
478 | return 'L'; | ||
479 | if (skb->len < i) | ||
480 | return 'N'; | ||
481 | if ((skb->len - i) > l2->maxlen) | ||
482 | return 'O'; | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | int | ||
487 | super_error(struct layer2 *l2, struct sk_buff *skb) | ||
488 | { | ||
489 | if (skb->len != l2addrsize(l2) + | ||
490 | (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1)) | ||
491 | return 'N'; | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | int | ||
496 | unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) | ||
497 | { | ||
498 | int rsp = (*skb->data & 0x2) >> 1; | ||
499 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
500 | rsp = !rsp; | ||
501 | if (rsp != wantrsp) | ||
502 | return 'L'; | ||
503 | if (skb->len != l2addrsize(l2) + 1) | ||
504 | return 'N'; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int | ||
509 | UI_error(struct layer2 *l2, struct sk_buff *skb) | ||
510 | { | ||
511 | int rsp = *skb->data & 0x2; | ||
512 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
513 | rsp = !rsp; | ||
514 | if (rsp) | ||
515 | return 'L'; | ||
516 | if (skb->len > l2->maxlen + l2addrsize(l2) + 1) | ||
517 | return 'O'; | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int | ||
522 | FRMR_error(struct layer2 *l2, struct sk_buff *skb) | ||
523 | { | ||
524 | u_int headers = l2addrsize(l2) + 1; | ||
525 | u_char *datap = skb->data + headers; | ||
526 | int rsp = *skb->data & 0x2; | ||
527 | |||
528 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
529 | rsp = !rsp; | ||
530 | if (!rsp) | ||
531 | return 'L'; | ||
532 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
533 | if (skb->len < headers + 5) | ||
534 | return 'N'; | ||
535 | else if (*debug & DEBUG_L2) | ||
536 | l2m_debug(&l2->l2m, | ||
537 | "FRMR information %2x %2x %2x %2x %2x", | ||
538 | datap[0], datap[1], datap[2], datap[3], datap[4]); | ||
539 | } else { | ||
540 | if (skb->len < headers + 3) | ||
541 | return 'N'; | ||
542 | else if (*debug & DEBUG_L2) | ||
543 | l2m_debug(&l2->l2m, | ||
544 | "FRMR information %2x %2x %2x", | ||
545 | datap[0], datap[1], datap[2]); | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static unsigned int | ||
551 | legalnr(struct layer2 *l2, unsigned int nr) | ||
552 | { | ||
553 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
554 | return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); | ||
555 | else | ||
556 | return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | setva(struct layer2 *l2, unsigned int nr) | ||
561 | { | ||
562 | struct sk_buff *skb; | ||
563 | |||
564 | while (l2->va != nr) { | ||
565 | l2->va++; | ||
566 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
567 | l2->va %= 128; | ||
568 | else | ||
569 | l2->va %= 8; | ||
570 | if (l2->windowar[l2->sow]) { | ||
571 | skb_trim(l2->windowar[l2->sow], 0); | ||
572 | skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]); | ||
573 | l2->windowar[l2->sow] = NULL; | ||
574 | } | ||
575 | l2->sow = (l2->sow + 1) % l2->window; | ||
576 | } | ||
577 | skb = skb_dequeue(&l2->tmp_queue); | ||
578 | while (skb) { | ||
579 | dev_kfree_skb(skb); | ||
580 | skb = skb_dequeue(&l2->tmp_queue); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void | ||
585 | send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) | ||
586 | { | ||
587 | u_char tmp[MAX_L2HEADER_LEN]; | ||
588 | int i; | ||
589 | |||
590 | i = sethdraddr(l2, tmp, cr); | ||
591 | tmp[i++] = cmd; | ||
592 | if (skb) | ||
593 | skb_trim(skb, 0); | ||
594 | else { | ||
595 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
596 | if (!skb) { | ||
597 | printk(KERN_WARNING "%s: can't alloc skbuff\n", | ||
598 | __func__); | ||
599 | return; | ||
600 | } | ||
601 | } | ||
602 | memcpy(skb_put(skb, i), tmp, i); | ||
603 | enqueue_super(l2, skb); | ||
604 | } | ||
605 | |||
606 | |||
607 | inline u_char | ||
608 | get_PollFlag(struct layer2 *l2, struct sk_buff *skb) | ||
609 | { | ||
610 | return skb->data[l2addrsize(l2)] & 0x10; | ||
611 | } | ||
612 | |||
613 | inline u_char | ||
614 | get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb) | ||
615 | { | ||
616 | u_char PF; | ||
617 | |||
618 | PF = get_PollFlag(l2, skb); | ||
619 | dev_kfree_skb(skb); | ||
620 | return PF; | ||
621 | } | ||
622 | |||
623 | inline void | ||
624 | start_t200(struct layer2 *l2, int i) | ||
625 | { | ||
626 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
627 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
628 | } | ||
629 | |||
630 | inline void | ||
631 | restart_t200(struct layer2 *l2, int i) | ||
632 | { | ||
633 | mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
634 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
635 | } | ||
636 | |||
637 | inline void | ||
638 | stop_t200(struct layer2 *l2, int i) | ||
639 | { | ||
640 | if (test_and_clear_bit(FLG_T200_RUN, &l2->flag)) | ||
641 | mISDN_FsmDelTimer(&l2->t200, i); | ||
642 | } | ||
643 | |||
644 | inline void | ||
645 | st5_dl_release_l2l3(struct layer2 *l2) | ||
646 | { | ||
647 | int pr; | ||
648 | |||
649 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
650 | pr = DL_RELEASE_CNF; | ||
651 | else | ||
652 | pr = DL_RELEASE_IND; | ||
653 | l2up_create(l2, pr, 0, NULL); | ||
654 | } | ||
655 | |||
656 | inline void | ||
657 | lapb_dl_release_l2l3(struct layer2 *l2, int f) | ||
658 | { | ||
659 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
660 | l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL); | ||
661 | l2up_create(l2, f, 0, NULL); | ||
662 | } | ||
663 | |||
664 | static void | ||
665 | establishlink(struct FsmInst *fi) | ||
666 | { | ||
667 | struct layer2 *l2 = fi->userdata; | ||
668 | u_char cmd; | ||
669 | |||
670 | clear_exception(l2); | ||
671 | l2->rc = 0; | ||
672 | cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10; | ||
673 | send_uframe(l2, NULL, cmd, CMD); | ||
674 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
675 | restart_t200(l2, 1); | ||
676 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
677 | freewin(l2); | ||
678 | mISDN_FsmChangeState(fi, ST_L2_5); | ||
679 | } | ||
680 | |||
681 | static void | ||
682 | l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) | ||
683 | { | ||
684 | struct sk_buff *skb = arg; | ||
685 | struct layer2 *l2 = fi->userdata; | ||
686 | |||
687 | if (get_PollFlagFree(l2, skb)) | ||
688 | l2mgr(l2, MDL_ERROR_IND, (void *) 'C'); | ||
689 | else | ||
690 | l2mgr(l2, MDL_ERROR_IND, (void *) 'D'); | ||
691 | |||
692 | } | ||
693 | |||
694 | static void | ||
695 | l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
696 | { | ||
697 | struct sk_buff *skb = arg; | ||
698 | struct layer2 *l2 = fi->userdata; | ||
699 | |||
700 | if (get_PollFlagFree(l2, skb)) | ||
701 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
702 | else { | ||
703 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
704 | establishlink(fi); | ||
705 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | static void | ||
710 | l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
711 | { | ||
712 | struct sk_buff *skb = arg; | ||
713 | struct layer2 *l2 = fi->userdata; | ||
714 | |||
715 | if (get_PollFlagFree(l2, skb)) | ||
716 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
717 | else | ||
718 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
719 | establishlink(fi); | ||
720 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
721 | } | ||
722 | |||
723 | static void | ||
724 | l2_go_st3(struct FsmInst *fi, int event, void *arg) | ||
725 | { | ||
726 | dev_kfree_skb((struct sk_buff *)arg); | ||
727 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
728 | } | ||
729 | |||
730 | static void | ||
731 | l2_mdl_assign(struct FsmInst *fi, int event, void *arg) | ||
732 | { | ||
733 | struct layer2 *l2 = fi->userdata; | ||
734 | |||
735 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
736 | dev_kfree_skb((struct sk_buff *)arg); | ||
737 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
738 | } | ||
739 | |||
740 | static void | ||
741 | l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) | ||
742 | { | ||
743 | struct layer2 *l2 = fi->userdata; | ||
744 | struct sk_buff *skb = arg; | ||
745 | |||
746 | skb_queue_tail(&l2->ui_queue, skb); | ||
747 | mISDN_FsmChangeState(fi, ST_L2_2); | ||
748 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
749 | } | ||
750 | |||
751 | static void | ||
752 | l2_queue_ui(struct FsmInst *fi, int event, void *arg) | ||
753 | { | ||
754 | struct layer2 *l2 = fi->userdata; | ||
755 | struct sk_buff *skb = arg; | ||
756 | |||
757 | skb_queue_tail(&l2->ui_queue, skb); | ||
758 | } | ||
759 | |||
760 | static void | ||
761 | tx_ui(struct layer2 *l2) | ||
762 | { | ||
763 | struct sk_buff *skb; | ||
764 | u_char header[MAX_L2HEADER_LEN]; | ||
765 | int i; | ||
766 | |||
767 | i = sethdraddr(l2, header, CMD); | ||
768 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
769 | header[1] = 0xff; /* tei 127 */ | ||
770 | header[i++] = UI; | ||
771 | while ((skb = skb_dequeue(&l2->ui_queue))) { | ||
772 | memcpy(skb_push(skb, i), header, i); | ||
773 | enqueue_ui(l2, skb); | ||
774 | } | ||
775 | } | ||
776 | |||
777 | static void | ||
778 | l2_send_ui(struct FsmInst *fi, int event, void *arg) | ||
779 | { | ||
780 | struct layer2 *l2 = fi->userdata; | ||
781 | struct sk_buff *skb = arg; | ||
782 | |||
783 | skb_queue_tail(&l2->ui_queue, skb); | ||
784 | tx_ui(l2); | ||
785 | } | ||
786 | |||
787 | static void | ||
788 | l2_got_ui(struct FsmInst *fi, int event, void *arg) | ||
789 | { | ||
790 | struct layer2 *l2 = fi->userdata; | ||
791 | struct sk_buff *skb = arg; | ||
792 | |||
793 | skb_pull(skb, l2headersize(l2, 1)); | ||
794 | /* | ||
795 | * in states 1-3 for broadcast | ||
796 | */ | ||
797 | |||
798 | if (l2->tm) | ||
799 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
800 | l2up(l2, DL_UNITDATA_IND, skb); | ||
801 | } | ||
802 | |||
803 | static void | ||
804 | l2_establish(struct FsmInst *fi, int event, void *arg) | ||
805 | { | ||
806 | struct sk_buff *skb = arg; | ||
807 | struct layer2 *l2 = fi->userdata; | ||
808 | |||
809 | establishlink(fi); | ||
810 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
811 | dev_kfree_skb(skb); | ||
812 | } | ||
813 | |||
814 | static void | ||
815 | l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) | ||
816 | { | ||
817 | struct sk_buff *skb = arg; | ||
818 | struct layer2 *l2 = fi->userdata; | ||
819 | |||
820 | skb_queue_purge(&l2->i_queue); | ||
821 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
822 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
823 | dev_kfree_skb(skb); | ||
824 | } | ||
825 | |||
826 | static void | ||
827 | l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) | ||
828 | { | ||
829 | struct sk_buff *skb = arg; | ||
830 | struct layer2 *l2 = fi->userdata; | ||
831 | |||
832 | skb_queue_purge(&l2->i_queue); | ||
833 | establishlink(fi); | ||
834 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
835 | dev_kfree_skb(skb); | ||
836 | } | ||
837 | |||
838 | static void | ||
839 | l2_release(struct FsmInst *fi, int event, void *arg) | ||
840 | { | ||
841 | struct layer2 *l2 = fi->userdata; | ||
842 | struct sk_buff *skb = arg; | ||
843 | |||
844 | skb_trim(skb, 0); | ||
845 | l2up(l2, DL_RELEASE_CNF, skb); | ||
846 | } | ||
847 | |||
848 | static void | ||
849 | l2_pend_rel(struct FsmInst *fi, int event, void *arg) | ||
850 | { | ||
851 | struct sk_buff *skb = arg; | ||
852 | struct layer2 *l2 = fi->userdata; | ||
853 | |||
854 | test_and_set_bit(FLG_PEND_REL, &l2->flag); | ||
855 | dev_kfree_skb(skb); | ||
856 | } | ||
857 | |||
858 | static void | ||
859 | l2_disconnect(struct FsmInst *fi, int event, void *arg) | ||
860 | { | ||
861 | struct layer2 *l2 = fi->userdata; | ||
862 | struct sk_buff *skb = arg; | ||
863 | |||
864 | skb_queue_purge(&l2->i_queue); | ||
865 | freewin(l2); | ||
866 | mISDN_FsmChangeState(fi, ST_L2_6); | ||
867 | l2->rc = 0; | ||
868 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
869 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
870 | restart_t200(l2, 2); | ||
871 | if (skb) | ||
872 | dev_kfree_skb(skb); | ||
873 | } | ||
874 | |||
875 | static void | ||
876 | l2_start_multi(struct FsmInst *fi, int event, void *arg) | ||
877 | { | ||
878 | struct layer2 *l2 = fi->userdata; | ||
879 | struct sk_buff *skb = arg; | ||
880 | |||
881 | l2->vs = 0; | ||
882 | l2->va = 0; | ||
883 | l2->vr = 0; | ||
884 | l2->sow = 0; | ||
885 | clear_exception(l2); | ||
886 | send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP); | ||
887 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
888 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
889 | skb_trim(skb, 0); | ||
890 | l2up(l2, DL_ESTABLISH_IND, skb); | ||
891 | if (l2->tm) | ||
892 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
893 | } | ||
894 | |||
895 | static void | ||
896 | l2_send_UA(struct FsmInst *fi, int event, void *arg) | ||
897 | { | ||
898 | struct layer2 *l2 = fi->userdata; | ||
899 | struct sk_buff *skb = arg; | ||
900 | |||
901 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
902 | } | ||
903 | |||
904 | static void | ||
905 | l2_send_DM(struct FsmInst *fi, int event, void *arg) | ||
906 | { | ||
907 | struct layer2 *l2 = fi->userdata; | ||
908 | struct sk_buff *skb = arg; | ||
909 | |||
910 | send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP); | ||
911 | } | ||
912 | |||
913 | static void | ||
914 | l2_restart_multi(struct FsmInst *fi, int event, void *arg) | ||
915 | { | ||
916 | struct layer2 *l2 = fi->userdata; | ||
917 | struct sk_buff *skb = arg; | ||
918 | int est = 0; | ||
919 | |||
920 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
921 | |||
922 | l2mgr(l2, MDL_ERROR_IND, (void *) 'F'); | ||
923 | |||
924 | if (l2->vs != l2->va) { | ||
925 | skb_queue_purge(&l2->i_queue); | ||
926 | est = 1; | ||
927 | } | ||
928 | |||
929 | clear_exception(l2); | ||
930 | l2->vs = 0; | ||
931 | l2->va = 0; | ||
932 | l2->vr = 0; | ||
933 | l2->sow = 0; | ||
934 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
935 | stop_t200(l2, 3); | ||
936 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
937 | |||
938 | if (est) | ||
939 | l2up_create(l2, DL_ESTABLISH_IND, 0, NULL); | ||
940 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
941 | * MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED, | ||
942 | * 0, NULL, 0); | ||
943 | */ | ||
944 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
945 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
946 | } | ||
947 | |||
948 | static void | ||
949 | l2_stop_multi(struct FsmInst *fi, int event, void *arg) | ||
950 | { | ||
951 | struct layer2 *l2 = fi->userdata; | ||
952 | struct sk_buff *skb = arg; | ||
953 | |||
954 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
955 | mISDN_FsmDelTimer(&l2->t203, 3); | ||
956 | stop_t200(l2, 4); | ||
957 | |||
958 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
959 | skb_queue_purge(&l2->i_queue); | ||
960 | freewin(l2); | ||
961 | lapb_dl_release_l2l3(l2, DL_RELEASE_IND); | ||
962 | if (l2->tm) | ||
963 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
964 | } | ||
965 | |||
966 | static void | ||
967 | l2_connected(struct FsmInst *fi, int event, void *arg) | ||
968 | { | ||
969 | struct layer2 *l2 = fi->userdata; | ||
970 | struct sk_buff *skb = arg; | ||
971 | int pr = -1; | ||
972 | |||
973 | if (!get_PollFlag(l2, skb)) { | ||
974 | l2_mdl_error_ua(fi, event, arg); | ||
975 | return; | ||
976 | } | ||
977 | dev_kfree_skb(skb); | ||
978 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
979 | l2_disconnect(fi, event, NULL); | ||
980 | if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) { | ||
981 | pr = DL_ESTABLISH_CNF; | ||
982 | } else if (l2->vs != l2->va) { | ||
983 | skb_queue_purge(&l2->i_queue); | ||
984 | pr = DL_ESTABLISH_IND; | ||
985 | } | ||
986 | stop_t200(l2, 5); | ||
987 | l2->vr = 0; | ||
988 | l2->vs = 0; | ||
989 | l2->va = 0; | ||
990 | l2->sow = 0; | ||
991 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
992 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4); | ||
993 | if (pr != -1) | ||
994 | l2up_create(l2, pr, 0, NULL); | ||
995 | |||
996 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
997 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
998 | |||
999 | if (l2->tm) | ||
1000 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
1001 | } | ||
1002 | |||
1003 | static void | ||
1004 | l2_released(struct FsmInst *fi, int event, void *arg) | ||
1005 | { | ||
1006 | struct layer2 *l2 = fi->userdata; | ||
1007 | struct sk_buff *skb = arg; | ||
1008 | |||
1009 | if (!get_PollFlag(l2, skb)) { | ||
1010 | l2_mdl_error_ua(fi, event, arg); | ||
1011 | return; | ||
1012 | } | ||
1013 | dev_kfree_skb(skb); | ||
1014 | stop_t200(l2, 6); | ||
1015 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1016 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1017 | if (l2->tm) | ||
1018 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1019 | } | ||
1020 | |||
1021 | static void | ||
1022 | l2_reestablish(struct FsmInst *fi, int event, void *arg) | ||
1023 | { | ||
1024 | struct layer2 *l2 = fi->userdata; | ||
1025 | struct sk_buff *skb = arg; | ||
1026 | |||
1027 | if (!get_PollFlagFree(l2, skb)) { | ||
1028 | establishlink(fi); | ||
1029 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | static void | ||
1034 | l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) | ||
1035 | { | ||
1036 | struct layer2 *l2 = fi->userdata; | ||
1037 | struct sk_buff *skb = arg; | ||
1038 | |||
1039 | if (get_PollFlagFree(l2, skb)) { | ||
1040 | stop_t200(l2, 7); | ||
1041 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
1042 | skb_queue_purge(&l2->i_queue); | ||
1043 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1044 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1045 | l2_newid(l2), 0, NULL); | ||
1046 | st5_dl_release_l2l3(l2); | ||
1047 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1048 | if (l2->tm) | ||
1049 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | static void | ||
1054 | l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) | ||
1055 | { | ||
1056 | struct layer2 *l2 = fi->userdata; | ||
1057 | struct sk_buff *skb = arg; | ||
1058 | |||
1059 | if (get_PollFlagFree(l2, skb)) { | ||
1060 | stop_t200(l2, 8); | ||
1061 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1062 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1063 | if (l2->tm) | ||
1064 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | void | ||
1069 | enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) | ||
1070 | { | ||
1071 | struct sk_buff *skb; | ||
1072 | u_char tmp[MAX_L2HEADER_LEN]; | ||
1073 | int i; | ||
1074 | |||
1075 | i = sethdraddr(l2, tmp, cr); | ||
1076 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1077 | tmp[i++] = typ; | ||
1078 | tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); | ||
1079 | } else | ||
1080 | tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); | ||
1081 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
1082 | if (!skb) { | ||
1083 | printk(KERN_WARNING | ||
1084 | "isdnl2 can't alloc sbbuff for enquiry_cr\n"); | ||
1085 | return; | ||
1086 | } | ||
1087 | memcpy(skb_put(skb, i), tmp, i); | ||
1088 | enqueue_super(l2, skb); | ||
1089 | } | ||
1090 | |||
1091 | inline void | ||
1092 | enquiry_response(struct layer2 *l2) | ||
1093 | { | ||
1094 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
1095 | enquiry_cr(l2, RNR, RSP, 1); | ||
1096 | else | ||
1097 | enquiry_cr(l2, RR, RSP, 1); | ||
1098 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1099 | } | ||
1100 | |||
1101 | inline void | ||
1102 | transmit_enquiry(struct layer2 *l2) | ||
1103 | { | ||
1104 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
1105 | enquiry_cr(l2, RNR, CMD, 1); | ||
1106 | else | ||
1107 | enquiry_cr(l2, RR, CMD, 1); | ||
1108 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1109 | start_t200(l2, 9); | ||
1110 | } | ||
1111 | |||
1112 | |||
1113 | static void | ||
1114 | nrerrorrecovery(struct FsmInst *fi) | ||
1115 | { | ||
1116 | struct layer2 *l2 = fi->userdata; | ||
1117 | |||
1118 | l2mgr(l2, MDL_ERROR_IND, (void *) 'J'); | ||
1119 | establishlink(fi); | ||
1120 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1121 | } | ||
1122 | |||
1123 | static void | ||
1124 | invoke_retransmission(struct layer2 *l2, unsigned int nr) | ||
1125 | { | ||
1126 | u_int p1; | ||
1127 | |||
1128 | if (l2->vs != nr) { | ||
1129 | while (l2->vs != nr) { | ||
1130 | (l2->vs)--; | ||
1131 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1132 | l2->vs %= 128; | ||
1133 | p1 = (l2->vs - l2->va) % 128; | ||
1134 | } else { | ||
1135 | l2->vs %= 8; | ||
1136 | p1 = (l2->vs - l2->va) % 8; | ||
1137 | } | ||
1138 | p1 = (p1 + l2->sow) % l2->window; | ||
1139 | if (l2->windowar[p1]) | ||
1140 | skb_queue_head(&l2->i_queue, l2->windowar[p1]); | ||
1141 | else | ||
1142 | printk(KERN_WARNING | ||
1143 | "%s: windowar[%d] is NULL\n", | ||
1144 | __func__, p1); | ||
1145 | l2->windowar[p1] = NULL; | ||
1146 | } | ||
1147 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | static void | ||
1152 | l2_st7_got_super(struct FsmInst *fi, int event, void *arg) | ||
1153 | { | ||
1154 | struct layer2 *l2 = fi->userdata; | ||
1155 | struct sk_buff *skb = arg; | ||
1156 | int PollFlag, rsp, typ = RR; | ||
1157 | unsigned int nr; | ||
1158 | |||
1159 | rsp = *skb->data & 0x2; | ||
1160 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
1161 | rsp = !rsp; | ||
1162 | |||
1163 | skb_pull(skb, l2addrsize(l2)); | ||
1164 | if (IsRNR(skb->data, l2)) { | ||
1165 | set_peer_busy(l2); | ||
1166 | typ = RNR; | ||
1167 | } else | ||
1168 | clear_peer_busy(l2); | ||
1169 | if (IsREJ(skb->data, l2)) | ||
1170 | typ = REJ; | ||
1171 | |||
1172 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1173 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
1174 | nr = skb->data[1] >> 1; | ||
1175 | } else { | ||
1176 | PollFlag = (skb->data[0] & 0x10); | ||
1177 | nr = (skb->data[0] >> 5) & 0x7; | ||
1178 | } | ||
1179 | dev_kfree_skb(skb); | ||
1180 | |||
1181 | if (PollFlag) { | ||
1182 | if (rsp) | ||
1183 | l2mgr(l2, MDL_ERROR_IND, (void *) 'A'); | ||
1184 | else | ||
1185 | enquiry_response(l2); | ||
1186 | } | ||
1187 | if (legalnr(l2, nr)) { | ||
1188 | if (typ == REJ) { | ||
1189 | setva(l2, nr); | ||
1190 | invoke_retransmission(l2, nr); | ||
1191 | stop_t200(l2, 10); | ||
1192 | if (mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
1193 | EV_L2_T203, NULL, 6)) | ||
1194 | l2m_debug(&l2->l2m, "Restart T203 ST7 REJ"); | ||
1195 | } else if ((nr == l2->vs) && (typ == RR)) { | ||
1196 | setva(l2, nr); | ||
1197 | stop_t200(l2, 11); | ||
1198 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
1199 | EV_L2_T203, NULL, 7); | ||
1200 | } else if ((l2->va != nr) || (typ == RNR)) { | ||
1201 | setva(l2, nr); | ||
1202 | if (typ != RR) | ||
1203 | mISDN_FsmDelTimer(&l2->t203, 9); | ||
1204 | restart_t200(l2, 12); | ||
1205 | } | ||
1206 | if (skb_queue_len(&l2->i_queue) && (typ == RR)) | ||
1207 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1208 | } else | ||
1209 | nrerrorrecovery(fi); | ||
1210 | } | ||
1211 | |||
1212 | static void | ||
1213 | l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) | ||
1214 | { | ||
1215 | struct layer2 *l2 = fi->userdata; | ||
1216 | struct sk_buff *skb = arg; | ||
1217 | |||
1218 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
1219 | skb_queue_tail(&l2->i_queue, skb); | ||
1220 | else | ||
1221 | dev_kfree_skb(skb); | ||
1222 | } | ||
1223 | |||
1224 | static void | ||
1225 | l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) | ||
1226 | { | ||
1227 | struct layer2 *l2 = fi->userdata; | ||
1228 | struct sk_buff *skb = arg; | ||
1229 | |||
1230 | skb_queue_tail(&l2->i_queue, skb); | ||
1231 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1232 | } | ||
1233 | |||
1234 | static void | ||
1235 | l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) | ||
1236 | { | ||
1237 | struct layer2 *l2 = fi->userdata; | ||
1238 | struct sk_buff *skb = arg; | ||
1239 | |||
1240 | skb_queue_tail(&l2->i_queue, skb); | ||
1241 | } | ||
1242 | |||
1243 | static void | ||
1244 | l2_got_iframe(struct FsmInst *fi, int event, void *arg) | ||
1245 | { | ||
1246 | struct layer2 *l2 = fi->userdata; | ||
1247 | struct sk_buff *skb = arg; | ||
1248 | int PollFlag, i; | ||
1249 | u_int ns, nr; | ||
1250 | |||
1251 | i = l2addrsize(l2); | ||
1252 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1253 | PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); | ||
1254 | ns = skb->data[i] >> 1; | ||
1255 | nr = (skb->data[i + 1] >> 1) & 0x7f; | ||
1256 | } else { | ||
1257 | PollFlag = (skb->data[i] & 0x10); | ||
1258 | ns = (skb->data[i] >> 1) & 0x7; | ||
1259 | nr = (skb->data[i] >> 5) & 0x7; | ||
1260 | } | ||
1261 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1262 | dev_kfree_skb(skb); | ||
1263 | if (PollFlag) | ||
1264 | enquiry_response(l2); | ||
1265 | } else { | ||
1266 | if (l2->vr == ns) { | ||
1267 | l2->vr++; | ||
1268 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
1269 | l2->vr %= 128; | ||
1270 | else | ||
1271 | l2->vr %= 8; | ||
1272 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
1273 | if (PollFlag) | ||
1274 | enquiry_response(l2); | ||
1275 | else | ||
1276 | test_and_set_bit(FLG_ACK_PEND, &l2->flag); | ||
1277 | skb_pull(skb, l2headersize(l2, 0)); | ||
1278 | l2up(l2, DL_DATA_IND, skb); | ||
1279 | } else { | ||
1280 | /* n(s)!=v(r) */ | ||
1281 | dev_kfree_skb(skb); | ||
1282 | if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { | ||
1283 | if (PollFlag) | ||
1284 | enquiry_response(l2); | ||
1285 | } else { | ||
1286 | enquiry_cr(l2, REJ, RSP, PollFlag); | ||
1287 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1288 | } | ||
1289 | } | ||
1290 | } | ||
1291 | if (legalnr(l2, nr)) { | ||
1292 | if (!test_bit(FLG_PEER_BUSY, &l2->flag) && | ||
1293 | (fi->state == ST_L2_7)) { | ||
1294 | if (nr == l2->vs) { | ||
1295 | stop_t200(l2, 13); | ||
1296 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
1297 | EV_L2_T203, NULL, 7); | ||
1298 | } else if (nr != l2->va) | ||
1299 | restart_t200(l2, 14); | ||
1300 | } | ||
1301 | setva(l2, nr); | ||
1302 | } else { | ||
1303 | nrerrorrecovery(fi); | ||
1304 | return; | ||
1305 | } | ||
1306 | if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7)) | ||
1307 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1308 | if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag)) | ||
1309 | enquiry_cr(l2, RR, RSP, 0); | ||
1310 | } | ||
1311 | |||
1312 | static void | ||
1313 | l2_got_tei(struct FsmInst *fi, int event, void *arg) | ||
1314 | { | ||
1315 | struct layer2 *l2 = fi->userdata; | ||
1316 | u_int info; | ||
1317 | |||
1318 | l2->tei = (signed char)(long)arg; | ||
1319 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
1320 | info = DL_INFO_L2_CONNECT; | ||
1321 | l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info); | ||
1322 | if (fi->state == ST_L2_3) { | ||
1323 | establishlink(fi); | ||
1324 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
1325 | } else | ||
1326 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1327 | if (skb_queue_len(&l2->ui_queue)) | ||
1328 | tx_ui(l2); | ||
1329 | } | ||
1330 | |||
1331 | static void | ||
1332 | l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1333 | { | ||
1334 | struct layer2 *l2 = fi->userdata; | ||
1335 | |||
1336 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1337 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1338 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1339 | } else if (l2->rc == l2->N200) { | ||
1340 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1341 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1342 | skb_queue_purge(&l2->i_queue); | ||
1343 | l2mgr(l2, MDL_ERROR_IND, (void *) 'G'); | ||
1344 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1345 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1346 | l2_newid(l2), 0, NULL); | ||
1347 | st5_dl_release_l2l3(l2); | ||
1348 | if (l2->tm) | ||
1349 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1350 | } else { | ||
1351 | l2->rc++; | ||
1352 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1353 | send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ? | ||
1354 | SABME : SABM) | 0x10, CMD); | ||
1355 | } | ||
1356 | } | ||
1357 | |||
1358 | static void | ||
1359 | l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1360 | { | ||
1361 | struct layer2 *l2 = fi->userdata; | ||
1362 | |||
1363 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1364 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1365 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1366 | } else if (l2->rc == l2->N200) { | ||
1367 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1368 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1369 | l2mgr(l2, MDL_ERROR_IND, (void *) 'H'); | ||
1370 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
1371 | if (l2->tm) | ||
1372 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1373 | } else { | ||
1374 | l2->rc++; | ||
1375 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, | ||
1376 | NULL, 9); | ||
1377 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | static void | ||
1382 | l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1383 | { | ||
1384 | struct layer2 *l2 = fi->userdata; | ||
1385 | |||
1386 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1387 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1388 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1389 | return; | ||
1390 | } | ||
1391 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1392 | l2->rc = 0; | ||
1393 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
1394 | transmit_enquiry(l2); | ||
1395 | l2->rc++; | ||
1396 | } | ||
1397 | |||
1398 | static void | ||
1399 | l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) | ||
1400 | { | ||
1401 | struct layer2 *l2 = fi->userdata; | ||
1402 | |||
1403 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1404 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1405 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
1406 | return; | ||
1407 | } | ||
1408 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
1409 | if (l2->rc == l2->N200) { | ||
1410 | l2mgr(l2, MDL_ERROR_IND, (void *) 'I'); | ||
1411 | establishlink(fi); | ||
1412 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1413 | } else { | ||
1414 | transmit_enquiry(l2); | ||
1415 | l2->rc++; | ||
1416 | } | ||
1417 | } | ||
1418 | |||
1419 | static void | ||
1420 | l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) | ||
1421 | { | ||
1422 | struct layer2 *l2 = fi->userdata; | ||
1423 | |||
1424 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
1425 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
1426 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9); | ||
1427 | return; | ||
1428 | } | ||
1429 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
1430 | transmit_enquiry(l2); | ||
1431 | l2->rc = 0; | ||
1432 | } | ||
1433 | |||
1434 | static void | ||
1435 | l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) | ||
1436 | { | ||
1437 | struct layer2 *l2 = fi->userdata; | ||
1438 | struct sk_buff *skb, *nskb, *oskb; | ||
1439 | u_char header[MAX_L2HEADER_LEN]; | ||
1440 | u_int i, p1; | ||
1441 | |||
1442 | if (!cansend(l2)) | ||
1443 | return; | ||
1444 | |||
1445 | skb = skb_dequeue(&l2->i_queue); | ||
1446 | if (!skb) | ||
1447 | return; | ||
1448 | |||
1449 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
1450 | p1 = (l2->vs - l2->va) % 128; | ||
1451 | else | ||
1452 | p1 = (l2->vs - l2->va) % 8; | ||
1453 | p1 = (p1 + l2->sow) % l2->window; | ||
1454 | if (l2->windowar[p1]) { | ||
1455 | printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", | ||
1456 | p1); | ||
1457 | dev_kfree_skb(l2->windowar[p1]); | ||
1458 | } | ||
1459 | l2->windowar[p1] = skb; | ||
1460 | i = sethdraddr(l2, header, CMD); | ||
1461 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1462 | header[i++] = l2->vs << 1; | ||
1463 | header[i++] = l2->vr << 1; | ||
1464 | l2->vs = (l2->vs + 1) % 128; | ||
1465 | } else { | ||
1466 | header[i++] = (l2->vr << 5) | (l2->vs << 1); | ||
1467 | l2->vs = (l2->vs + 1) % 8; | ||
1468 | } | ||
1469 | |||
1470 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
1471 | p1 = skb_headroom(nskb); | ||
1472 | if (p1 >= i) | ||
1473 | memcpy(skb_push(nskb, i), header, i); | ||
1474 | else { | ||
1475 | printk(KERN_WARNING | ||
1476 | "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); | ||
1477 | oskb = nskb; | ||
1478 | nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); | ||
1479 | if (!nskb) { | ||
1480 | dev_kfree_skb(oskb); | ||
1481 | printk(KERN_WARNING "%s: no skb mem\n", __func__); | ||
1482 | return; | ||
1483 | } | ||
1484 | memcpy(skb_put(nskb, i), header, i); | ||
1485 | memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len); | ||
1486 | dev_kfree_skb(oskb); | ||
1487 | } | ||
1488 | l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); | ||
1489 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1490 | if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { | ||
1491 | mISDN_FsmDelTimer(&l2->t203, 13); | ||
1492 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11); | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | static void | ||
1497 | l2_st8_got_super(struct FsmInst *fi, int event, void *arg) | ||
1498 | { | ||
1499 | struct layer2 *l2 = fi->userdata; | ||
1500 | struct sk_buff *skb = arg; | ||
1501 | int PollFlag, rsp, rnr = 0; | ||
1502 | unsigned int nr; | ||
1503 | |||
1504 | rsp = *skb->data & 0x2; | ||
1505 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
1506 | rsp = !rsp; | ||
1507 | |||
1508 | skb_pull(skb, l2addrsize(l2)); | ||
1509 | |||
1510 | if (IsRNR(skb->data, l2)) { | ||
1511 | set_peer_busy(l2); | ||
1512 | rnr = 1; | ||
1513 | } else | ||
1514 | clear_peer_busy(l2); | ||
1515 | |||
1516 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
1517 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
1518 | nr = skb->data[1] >> 1; | ||
1519 | } else { | ||
1520 | PollFlag = (skb->data[0] & 0x10); | ||
1521 | nr = (skb->data[0] >> 5) & 0x7; | ||
1522 | } | ||
1523 | dev_kfree_skb(skb); | ||
1524 | if (rsp && PollFlag) { | ||
1525 | if (legalnr(l2, nr)) { | ||
1526 | if (rnr) { | ||
1527 | restart_t200(l2, 15); | ||
1528 | } else { | ||
1529 | stop_t200(l2, 16); | ||
1530 | mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
1531 | EV_L2_T203, NULL, 5); | ||
1532 | setva(l2, nr); | ||
1533 | } | ||
1534 | invoke_retransmission(l2, nr); | ||
1535 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
1536 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
1537 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
1538 | } else | ||
1539 | nrerrorrecovery(fi); | ||
1540 | } else { | ||
1541 | if (!rsp && PollFlag) | ||
1542 | enquiry_response(l2); | ||
1543 | if (legalnr(l2, nr)) | ||
1544 | setva(l2, nr); | ||
1545 | else | ||
1546 | nrerrorrecovery(fi); | ||
1547 | } | ||
1548 | } | ||
1549 | |||
1550 | static void | ||
1551 | l2_got_FRMR(struct FsmInst *fi, int event, void *arg) | ||
1552 | { | ||
1553 | struct layer2 *l2 = fi->userdata; | ||
1554 | struct sk_buff *skb = arg; | ||
1555 | |||
1556 | skb_pull(skb, l2addrsize(l2) + 1); | ||
1557 | |||
1558 | if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ | ||
1559 | (IsUA(skb->data) && (fi->state == ST_L2_7))) { | ||
1560 | l2mgr(l2, MDL_ERROR_IND, (void *) 'K'); | ||
1561 | establishlink(fi); | ||
1562 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1563 | } | ||
1564 | dev_kfree_skb(skb); | ||
1565 | } | ||
1566 | |||
1567 | static void | ||
1568 | l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1569 | { | ||
1570 | struct layer2 *l2 = fi->userdata; | ||
1571 | |||
1572 | skb_queue_purge(&l2->ui_queue); | ||
1573 | l2->tei = GROUP_TEI; | ||
1574 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1575 | } | ||
1576 | |||
1577 | static void | ||
1578 | l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1579 | { | ||
1580 | struct layer2 *l2 = fi->userdata; | ||
1581 | |||
1582 | skb_queue_purge(&l2->ui_queue); | ||
1583 | l2->tei = GROUP_TEI; | ||
1584 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1585 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1586 | } | ||
1587 | |||
1588 | static void | ||
1589 | l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1590 | { | ||
1591 | struct layer2 *l2 = fi->userdata; | ||
1592 | |||
1593 | skb_queue_purge(&l2->i_queue); | ||
1594 | skb_queue_purge(&l2->ui_queue); | ||
1595 | freewin(l2); | ||
1596 | l2->tei = GROUP_TEI; | ||
1597 | stop_t200(l2, 17); | ||
1598 | st5_dl_release_l2l3(l2); | ||
1599 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1600 | } | ||
1601 | |||
1602 | static void | ||
1603 | l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1604 | { | ||
1605 | struct layer2 *l2 = fi->userdata; | ||
1606 | |||
1607 | skb_queue_purge(&l2->ui_queue); | ||
1608 | l2->tei = GROUP_TEI; | ||
1609 | stop_t200(l2, 18); | ||
1610 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1611 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1612 | } | ||
1613 | |||
1614 | static void | ||
1615 | l2_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
1616 | { | ||
1617 | struct layer2 *l2 = fi->userdata; | ||
1618 | |||
1619 | skb_queue_purge(&l2->i_queue); | ||
1620 | skb_queue_purge(&l2->ui_queue); | ||
1621 | freewin(l2); | ||
1622 | l2->tei = GROUP_TEI; | ||
1623 | stop_t200(l2, 17); | ||
1624 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
1625 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
1626 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
1627 | * MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED, | ||
1628 | * 0, NULL, 0); | ||
1629 | */ | ||
1630 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
1631 | } | ||
1632 | |||
1633 | static void | ||
1634 | l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1635 | { | ||
1636 | struct layer2 *l2 = fi->userdata; | ||
1637 | struct sk_buff *skb = arg; | ||
1638 | |||
1639 | skb_queue_purge(&l2->i_queue); | ||
1640 | skb_queue_purge(&l2->ui_queue); | ||
1641 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
1642 | l2up(l2, DL_RELEASE_IND, skb); | ||
1643 | else | ||
1644 | dev_kfree_skb(skb); | ||
1645 | } | ||
1646 | |||
1647 | static void | ||
1648 | l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1649 | { | ||
1650 | struct layer2 *l2 = fi->userdata; | ||
1651 | struct sk_buff *skb = arg; | ||
1652 | |||
1653 | skb_queue_purge(&l2->i_queue); | ||
1654 | skb_queue_purge(&l2->ui_queue); | ||
1655 | freewin(l2); | ||
1656 | stop_t200(l2, 19); | ||
1657 | st5_dl_release_l2l3(l2); | ||
1658 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1659 | if (l2->tm) | ||
1660 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1661 | dev_kfree_skb(skb); | ||
1662 | } | ||
1663 | |||
1664 | static void | ||
1665 | l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1666 | { | ||
1667 | struct layer2 *l2 = fi->userdata; | ||
1668 | struct sk_buff *skb = arg; | ||
1669 | |||
1670 | skb_queue_purge(&l2->ui_queue); | ||
1671 | stop_t200(l2, 20); | ||
1672 | l2up(l2, DL_RELEASE_CNF, skb); | ||
1673 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1674 | if (l2->tm) | ||
1675 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1676 | } | ||
1677 | |||
1678 | static void | ||
1679 | l2_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
1680 | { | ||
1681 | struct layer2 *l2 = fi->userdata; | ||
1682 | struct sk_buff *skb = arg; | ||
1683 | |||
1684 | skb_queue_purge(&l2->i_queue); | ||
1685 | skb_queue_purge(&l2->ui_queue); | ||
1686 | freewin(l2); | ||
1687 | stop_t200(l2, 19); | ||
1688 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
1689 | l2up(l2, DL_RELEASE_IND, skb); | ||
1690 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
1691 | if (l2->tm) | ||
1692 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
1693 | } | ||
1694 | |||
1695 | static void | ||
1696 | l2_set_own_busy(struct FsmInst *fi, int event, void *arg) | ||
1697 | { | ||
1698 | struct layer2 *l2 = fi->userdata; | ||
1699 | struct sk_buff *skb = arg; | ||
1700 | |||
1701 | if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1702 | enquiry_cr(l2, RNR, RSP, 0); | ||
1703 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1704 | } | ||
1705 | if (skb) | ||
1706 | dev_kfree_skb(skb); | ||
1707 | } | ||
1708 | |||
1709 | static void | ||
1710 | l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) | ||
1711 | { | ||
1712 | struct layer2 *l2 = fi->userdata; | ||
1713 | struct sk_buff *skb = arg; | ||
1714 | |||
1715 | if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
1716 | enquiry_cr(l2, RR, RSP, 0); | ||
1717 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
1718 | } | ||
1719 | if (skb) | ||
1720 | dev_kfree_skb(skb); | ||
1721 | } | ||
1722 | |||
1723 | static void | ||
1724 | l2_frame_error(struct FsmInst *fi, int event, void *arg) | ||
1725 | { | ||
1726 | struct layer2 *l2 = fi->userdata; | ||
1727 | |||
1728 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
1729 | } | ||
1730 | |||
1731 | static void | ||
1732 | l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) | ||
1733 | { | ||
1734 | struct layer2 *l2 = fi->userdata; | ||
1735 | |||
1736 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
1737 | establishlink(fi); | ||
1738 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
1739 | } | ||
1740 | |||
1741 | static struct FsmNode L2FnList[] = | ||
1742 | { | ||
1743 | {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, | ||
1744 | {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, | ||
1745 | {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, | ||
1746 | {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, | ||
1747 | {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
1748 | {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
1749 | {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, | ||
1750 | {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, | ||
1751 | {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
1752 | {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
1753 | {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, | ||
1754 | {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, | ||
1755 | {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, | ||
1756 | {ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign}, | ||
1757 | {ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
1758 | {ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
1759 | {ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1760 | {ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1761 | {ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1762 | {ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1763 | {ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
1764 | {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1765 | {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1766 | {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
1767 | {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, | ||
1768 | {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, | ||
1769 | {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, | ||
1770 | {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, | ||
1771 | {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, | ||
1772 | {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
1773 | {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
1774 | {ST_L2_4, EV_L2_SABME, l2_start_multi}, | ||
1775 | {ST_L2_5, EV_L2_SABME, l2_send_UA}, | ||
1776 | {ST_L2_6, EV_L2_SABME, l2_send_DM}, | ||
1777 | {ST_L2_7, EV_L2_SABME, l2_restart_multi}, | ||
1778 | {ST_L2_8, EV_L2_SABME, l2_restart_multi}, | ||
1779 | {ST_L2_4, EV_L2_DISC, l2_send_DM}, | ||
1780 | {ST_L2_5, EV_L2_DISC, l2_send_DM}, | ||
1781 | {ST_L2_6, EV_L2_DISC, l2_send_UA}, | ||
1782 | {ST_L2_7, EV_L2_DISC, l2_stop_multi}, | ||
1783 | {ST_L2_8, EV_L2_DISC, l2_stop_multi}, | ||
1784 | {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, | ||
1785 | {ST_L2_5, EV_L2_UA, l2_connected}, | ||
1786 | {ST_L2_6, EV_L2_UA, l2_released}, | ||
1787 | {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, | ||
1788 | {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, | ||
1789 | {ST_L2_4, EV_L2_DM, l2_reestablish}, | ||
1790 | {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, | ||
1791 | {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, | ||
1792 | {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, | ||
1793 | {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, | ||
1794 | {ST_L2_1, EV_L2_UI, l2_got_ui}, | ||
1795 | {ST_L2_2, EV_L2_UI, l2_got_ui}, | ||
1796 | {ST_L2_3, EV_L2_UI, l2_got_ui}, | ||
1797 | {ST_L2_4, EV_L2_UI, l2_got_ui}, | ||
1798 | {ST_L2_5, EV_L2_UI, l2_got_ui}, | ||
1799 | {ST_L2_6, EV_L2_UI, l2_got_ui}, | ||
1800 | {ST_L2_7, EV_L2_UI, l2_got_ui}, | ||
1801 | {ST_L2_8, EV_L2_UI, l2_got_ui}, | ||
1802 | {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, | ||
1803 | {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, | ||
1804 | {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, | ||
1805 | {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, | ||
1806 | {ST_L2_7, EV_L2_I, l2_got_iframe}, | ||
1807 | {ST_L2_8, EV_L2_I, l2_got_iframe}, | ||
1808 | {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, | ||
1809 | {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, | ||
1810 | {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, | ||
1811 | {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, | ||
1812 | {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, | ||
1813 | {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, | ||
1814 | {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
1815 | {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
1816 | {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
1817 | {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
1818 | {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1819 | {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1820 | {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
1821 | {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
1822 | {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
1823 | {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
1824 | {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, | ||
1825 | {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, | ||
1826 | {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
1827 | {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, | ||
1828 | {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, | ||
1829 | {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
1830 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
1831 | }; | ||
1832 | |||
1833 | #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) | ||
1834 | |||
1835 | static int | ||
1836 | ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) | ||
1837 | { | ||
1838 | u_char *datap = skb->data; | ||
1839 | int ret = -EINVAL; | ||
1840 | int psapi, ptei; | ||
1841 | u_int l; | ||
1842 | int c = 0; | ||
1843 | |||
1844 | l = l2addrsize(l2); | ||
1845 | if (skb->len <= l) { | ||
1846 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N'); | ||
1847 | return ret; | ||
1848 | } | ||
1849 | if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */ | ||
1850 | psapi = *datap++; | ||
1851 | ptei = *datap++; | ||
1852 | if ((psapi & 1) || !(ptei & 1)) { | ||
1853 | printk(KERN_WARNING | ||
1854 | "l2 D-channel frame wrong EA0/EA1\n"); | ||
1855 | return ret; | ||
1856 | } | ||
1857 | psapi >>= 2; | ||
1858 | ptei >>= 1; | ||
1859 | if (psapi != l2->sapi) { | ||
1860 | /* not our bussiness | ||
1861 | * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", | ||
1862 | * __func__, | ||
1863 | * psapi, l2->sapi); | ||
1864 | */ | ||
1865 | dev_kfree_skb(skb); | ||
1866 | return 0; | ||
1867 | } | ||
1868 | if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { | ||
1869 | /* not our bussiness | ||
1870 | * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", | ||
1871 | * __func__, | ||
1872 | * ptei, l2->tei, psapi); | ||
1873 | */ | ||
1874 | dev_kfree_skb(skb); | ||
1875 | return 0; | ||
1876 | } | ||
1877 | } else | ||
1878 | datap += l; | ||
1879 | if (!(*datap & 1)) { /* I-Frame */ | ||
1880 | c = iframe_error(l2, skb); | ||
1881 | if (!c) | ||
1882 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb); | ||
1883 | } else if (IsSFrame(datap, l2)) { /* S-Frame */ | ||
1884 | c = super_error(l2, skb); | ||
1885 | if (!c) | ||
1886 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb); | ||
1887 | } else if (IsUI(datap)) { | ||
1888 | c = UI_error(l2, skb); | ||
1889 | if (!c) | ||
1890 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb); | ||
1891 | } else if (IsSABME(datap, l2)) { | ||
1892 | c = unnum_error(l2, skb, CMD); | ||
1893 | if (!c) | ||
1894 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb); | ||
1895 | } else if (IsUA(datap)) { | ||
1896 | c = unnum_error(l2, skb, RSP); | ||
1897 | if (!c) | ||
1898 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb); | ||
1899 | } else if (IsDISC(datap)) { | ||
1900 | c = unnum_error(l2, skb, CMD); | ||
1901 | if (!c) | ||
1902 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb); | ||
1903 | } else if (IsDM(datap)) { | ||
1904 | c = unnum_error(l2, skb, RSP); | ||
1905 | if (!c) | ||
1906 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb); | ||
1907 | } else if (IsFRMR(datap)) { | ||
1908 | c = FRMR_error(l2, skb); | ||
1909 | if (!c) | ||
1910 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb); | ||
1911 | } else | ||
1912 | c = 'L'; | ||
1913 | if (c) { | ||
1914 | printk(KERN_WARNING "l2 D-channel frame error %c\n", c); | ||
1915 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); | ||
1916 | } | ||
1917 | return ret; | ||
1918 | } | ||
1919 | |||
1920 | static int | ||
1921 | l2_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1922 | { | ||
1923 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
1924 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1925 | int ret = -EINVAL; | ||
1926 | |||
1927 | if (*debug & DEBUG_L2_RECV) | ||
1928 | printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", | ||
1929 | __func__, hh->prim, hh->id, l2->tei); | ||
1930 | switch (hh->prim) { | ||
1931 | case PH_DATA_IND: | ||
1932 | ret = ph_data_indication(l2, hh, skb); | ||
1933 | break; | ||
1934 | case PH_DATA_CNF: | ||
1935 | ret = ph_data_confirm(l2, hh, skb); | ||
1936 | break; | ||
1937 | case PH_ACTIVATE_IND: | ||
1938 | test_and_set_bit(FLG_L1_ACTIV, &l2->flag); | ||
1939 | l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL); | ||
1940 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
1941 | ret = mISDN_FsmEvent(&l2->l2m, | ||
1942 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
1943 | break; | ||
1944 | case PH_DEACTIVATE_IND: | ||
1945 | test_and_clear_bit(FLG_L1_ACTIV, &l2->flag); | ||
1946 | l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL); | ||
1947 | ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb); | ||
1948 | break; | ||
1949 | case MPH_INFORMATION_IND: | ||
1950 | if (!l2->up) | ||
1951 | break; | ||
1952 | ret = l2->up->send(l2->up, skb); | ||
1953 | break; | ||
1954 | case DL_DATA_REQ: | ||
1955 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb); | ||
1956 | break; | ||
1957 | case DL_UNITDATA_REQ: | ||
1958 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb); | ||
1959 | break; | ||
1960 | case DL_ESTABLISH_REQ: | ||
1961 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1962 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
1963 | if (test_bit(FLG_L1_ACTIV, &l2->flag)) { | ||
1964 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
1965 | test_bit(FLG_ORIG, &l2->flag)) | ||
1966 | ret = mISDN_FsmEvent(&l2->l2m, | ||
1967 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
1968 | } else { | ||
1969 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
1970 | test_bit(FLG_ORIG, &l2->flag)) { | ||
1971 | test_and_set_bit(FLG_ESTAB_PEND, | ||
1972 | &l2->flag); | ||
1973 | } | ||
1974 | ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2), | ||
1975 | skb); | ||
1976 | } | ||
1977 | break; | ||
1978 | case DL_RELEASE_REQ: | ||
1979 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
1980 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
1981 | l2_newid(l2), 0, NULL); | ||
1982 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, | ||
1983 | skb); | ||
1984 | break; | ||
1985 | default: | ||
1986 | if (*debug & DEBUG_L2) | ||
1987 | l2m_debug(&l2->l2m, "l2 unknown pr %04x", | ||
1988 | hh->prim); | ||
1989 | } | ||
1990 | if (ret) { | ||
1991 | dev_kfree_skb(skb); | ||
1992 | ret = 0; | ||
1993 | } | ||
1994 | return ret; | ||
1995 | } | ||
1996 | |||
1997 | int | ||
1998 | tei_l2(struct layer2 *l2, u_int cmd, u_long arg) | ||
1999 | { | ||
2000 | int ret = -EINVAL; | ||
2001 | |||
2002 | if (*debug & DEBUG_L2_TEI) | ||
2003 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
2004 | switch (cmd) { | ||
2005 | case (MDL_ASSIGN_REQ): | ||
2006 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); | ||
2007 | break; | ||
2008 | case (MDL_REMOVE_REQ): | ||
2009 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL); | ||
2010 | break; | ||
2011 | case (MDL_ERROR_IND): | ||
2012 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
2013 | break; | ||
2014 | case (MDL_ERROR_RSP): | ||
2015 | /* ETS 300-125 5.3.2.1 Test: TC13010 */ | ||
2016 | printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); | ||
2017 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
2018 | break; | ||
2019 | } | ||
2020 | return ret; | ||
2021 | } | ||
2022 | |||
2023 | static void | ||
2024 | release_l2(struct layer2 *l2) | ||
2025 | { | ||
2026 | mISDN_FsmDelTimer(&l2->t200, 21); | ||
2027 | mISDN_FsmDelTimer(&l2->t203, 16); | ||
2028 | skb_queue_purge(&l2->i_queue); | ||
2029 | skb_queue_purge(&l2->ui_queue); | ||
2030 | skb_queue_purge(&l2->down_queue); | ||
2031 | ReleaseWin(l2); | ||
2032 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
2033 | release_tei(l2); | ||
2034 | if (l2->ch.st) | ||
2035 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, | ||
2036 | CLOSE_CHANNEL, NULL); | ||
2037 | } | ||
2038 | kfree(l2); | ||
2039 | } | ||
2040 | |||
2041 | static int | ||
2042 | l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
2043 | { | ||
2044 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
2045 | u_int info; | ||
2046 | |||
2047 | if (*debug & DEBUG_L2_CTRL) | ||
2048 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
2049 | |||
2050 | switch (cmd) { | ||
2051 | case OPEN_CHANNEL: | ||
2052 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
2053 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
2054 | info = DL_INFO_L2_CONNECT; | ||
2055 | l2up_create(l2, DL_INFORMATION_IND, | ||
2056 | sizeof(info), &info); | ||
2057 | } | ||
2058 | break; | ||
2059 | case CLOSE_CHANNEL: | ||
2060 | if (l2->ch.peer) | ||
2061 | l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL); | ||
2062 | release_l2(l2); | ||
2063 | break; | ||
2064 | } | ||
2065 | return 0; | ||
2066 | } | ||
2067 | |||
2068 | struct layer2 * | ||
2069 | create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) | ||
2070 | { | ||
2071 | struct layer2 *l2; | ||
2072 | struct channel_req rq; | ||
2073 | |||
2074 | l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL); | ||
2075 | if (!l2) { | ||
2076 | printk(KERN_ERR "kzalloc layer2 failed\n"); | ||
2077 | return NULL; | ||
2078 | } | ||
2079 | l2->next_id = 1; | ||
2080 | l2->down_id = MISDN_ID_NONE; | ||
2081 | l2->up = ch; | ||
2082 | l2->ch.st = ch->st; | ||
2083 | l2->ch.send = l2_send; | ||
2084 | l2->ch.ctrl = l2_ctrl; | ||
2085 | switch (protocol) { | ||
2086 | case ISDN_P_LAPD_NT: | ||
2087 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
2088 | test_and_set_bit(FLG_LAPD_NET, &l2->flag); | ||
2089 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
2090 | l2->sapi = 0; | ||
2091 | l2->maxlen = MAX_DFRAME_LEN; | ||
2092 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2093 | l2->window = 7; | ||
2094 | else | ||
2095 | l2->window = 1; | ||
2096 | if (test_bit(OPTION_L2_PTP, &options)) | ||
2097 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
2098 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
2099 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
2100 | l2->tei = (u_int)arg; | ||
2101 | l2->T200 = 1000; | ||
2102 | l2->N200 = 3; | ||
2103 | l2->T203 = 10000; | ||
2104 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2105 | rq.protocol = ISDN_P_NT_E1; | ||
2106 | else | ||
2107 | rq.protocol = ISDN_P_NT_S0; | ||
2108 | rq.adr.channel = 0; | ||
2109 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
2110 | break; | ||
2111 | case ISDN_P_LAPD_TE: | ||
2112 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
2113 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
2114 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
2115 | l2->sapi = 0; | ||
2116 | l2->maxlen = MAX_DFRAME_LEN; | ||
2117 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2118 | l2->window = 7; | ||
2119 | else | ||
2120 | l2->window = 1; | ||
2121 | if (test_bit(OPTION_L2_PTP, &options)) | ||
2122 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
2123 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
2124 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
2125 | l2->tei = (u_int)arg; | ||
2126 | l2->T200 = 1000; | ||
2127 | l2->N200 = 3; | ||
2128 | l2->T203 = 10000; | ||
2129 | if (test_bit(OPTION_L2_PMX, &options)) | ||
2130 | rq.protocol = ISDN_P_TE_E1; | ||
2131 | else | ||
2132 | rq.protocol = ISDN_P_TE_S0; | ||
2133 | rq.adr.channel = 0; | ||
2134 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
2135 | break; | ||
2136 | case ISDN_P_B_X75SLP: | ||
2137 | test_and_set_bit(FLG_LAPB, &l2->flag); | ||
2138 | l2->window = 7; | ||
2139 | l2->maxlen = MAX_DATA_SIZE; | ||
2140 | l2->T200 = 1000; | ||
2141 | l2->N200 = 4; | ||
2142 | l2->T203 = 5000; | ||
2143 | l2->addr.A = 3; | ||
2144 | l2->addr.B = 1; | ||
2145 | break; | ||
2146 | default: | ||
2147 | printk(KERN_ERR "layer2 create failed prt %x\n", | ||
2148 | protocol); | ||
2149 | kfree(l2); | ||
2150 | return NULL; | ||
2151 | } | ||
2152 | skb_queue_head_init(&l2->i_queue); | ||
2153 | skb_queue_head_init(&l2->ui_queue); | ||
2154 | skb_queue_head_init(&l2->down_queue); | ||
2155 | skb_queue_head_init(&l2->tmp_queue); | ||
2156 | InitWin(l2); | ||
2157 | l2->l2m.fsm = &l2fsm; | ||
2158 | if (test_bit(FLG_LAPB, &l2->flag) || | ||
2159 | test_bit(FLG_PTP, &l2->flag) || | ||
2160 | test_bit(FLG_LAPD_NET, &l2->flag)) | ||
2161 | l2->l2m.state = ST_L2_4; | ||
2162 | else | ||
2163 | l2->l2m.state = ST_L2_1; | ||
2164 | l2->l2m.debug = *debug; | ||
2165 | l2->l2m.userdata = l2; | ||
2166 | l2->l2m.userint = 0; | ||
2167 | l2->l2m.printdebug = l2m_debug; | ||
2168 | |||
2169 | mISDN_FsmInitTimer(&l2->l2m, &l2->t200); | ||
2170 | mISDN_FsmInitTimer(&l2->l2m, &l2->t203); | ||
2171 | return l2; | ||
2172 | } | ||
2173 | |||
2174 | static int | ||
2175 | x75create(struct channel_req *crq) | ||
2176 | { | ||
2177 | struct layer2 *l2; | ||
2178 | |||
2179 | if (crq->protocol != ISDN_P_B_X75SLP) | ||
2180 | return -EPROTONOSUPPORT; | ||
2181 | l2 = create_l2(crq->ch, crq->protocol, 0, 0); | ||
2182 | if (!l2) | ||
2183 | return -ENOMEM; | ||
2184 | crq->ch = &l2->ch; | ||
2185 | crq->protocol = ISDN_P_B_HDLC; | ||
2186 | return 0; | ||
2187 | } | ||
2188 | |||
2189 | static struct Bprotocol X75SLP = { | ||
2190 | .Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)), | ||
2191 | .name = "X75SLP", | ||
2192 | .create = x75create | ||
2193 | }; | ||
2194 | |||
2195 | int | ||
2196 | Isdnl2_Init(u_int *deb) | ||
2197 | { | ||
2198 | debug = deb; | ||
2199 | mISDN_register_Bprotocol(&X75SLP); | ||
2200 | l2fsm.state_count = L2_STATE_COUNT; | ||
2201 | l2fsm.event_count = L2_EVENT_COUNT; | ||
2202 | l2fsm.strEvent = strL2Event; | ||
2203 | l2fsm.strState = strL2State; | ||
2204 | mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); | ||
2205 | TEIInit(deb); | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | void | ||
2210 | Isdnl2_cleanup(void) | ||
2211 | { | ||
2212 | mISDN_unregister_Bprotocol(&X75SLP); | ||
2213 | TEIFree(); | ||
2214 | mISDN_FsmFree(&l2fsm); | ||
2215 | } | ||
2216 | |||
diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h new file mode 100644 index 000000000000..de2dd02056a3 --- /dev/null +++ b/drivers/isdn/mISDN/layer2.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Layer 2 defines | ||
3 | * | ||
4 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/mISDNif.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include "fsm.h" | ||
20 | |||
21 | #define MAX_WINDOW 8 | ||
22 | |||
23 | struct manager { | ||
24 | struct mISDNchannel ch; | ||
25 | struct mISDNchannel bcast; | ||
26 | u_long options; | ||
27 | struct list_head layer2; | ||
28 | rwlock_t lock; | ||
29 | struct FsmInst deact; | ||
30 | struct FsmTimer datimer; | ||
31 | struct sk_buff_head sendq; | ||
32 | struct mISDNchannel *up; | ||
33 | u_int nextid; | ||
34 | u_int lastid; | ||
35 | }; | ||
36 | |||
37 | struct teimgr { | ||
38 | int ri; | ||
39 | int rcnt; | ||
40 | struct FsmInst tei_m; | ||
41 | struct FsmTimer timer; | ||
42 | int tval, nval; | ||
43 | struct layer2 *l2; | ||
44 | struct manager *mgr; | ||
45 | }; | ||
46 | |||
47 | struct laddr { | ||
48 | u_char A; | ||
49 | u_char B; | ||
50 | }; | ||
51 | |||
52 | struct layer2 { | ||
53 | struct list_head list; | ||
54 | struct mISDNchannel ch; | ||
55 | u_long flag; | ||
56 | int id; | ||
57 | struct mISDNchannel *up; | ||
58 | signed char sapi; | ||
59 | signed char tei; | ||
60 | struct laddr addr; | ||
61 | u_int maxlen; | ||
62 | struct teimgr *tm; | ||
63 | u_int vs, va, vr; | ||
64 | int rc; | ||
65 | u_int window; | ||
66 | u_int sow; | ||
67 | struct FsmInst l2m; | ||
68 | struct FsmTimer t200, t203; | ||
69 | int T200, N200, T203; | ||
70 | u_int next_id; | ||
71 | u_int down_id; | ||
72 | struct sk_buff *windowar[MAX_WINDOW]; | ||
73 | struct sk_buff_head i_queue; | ||
74 | struct sk_buff_head ui_queue; | ||
75 | struct sk_buff_head down_queue; | ||
76 | struct sk_buff_head tmp_queue; | ||
77 | }; | ||
78 | |||
79 | enum { | ||
80 | ST_L2_1, | ||
81 | ST_L2_2, | ||
82 | ST_L2_3, | ||
83 | ST_L2_4, | ||
84 | ST_L2_5, | ||
85 | ST_L2_6, | ||
86 | ST_L2_7, | ||
87 | ST_L2_8, | ||
88 | }; | ||
89 | |||
90 | #define L2_STATE_COUNT (ST_L2_8+1) | ||
91 | |||
92 | extern struct layer2 *create_l2(struct mISDNchannel *, u_int, | ||
93 | u_long, u_long); | ||
94 | extern int tei_l2(struct layer2 *, u_int, u_long arg); | ||
95 | |||
96 | |||
97 | /* from tei.c */ | ||
98 | extern int l2_tei(struct layer2 *, u_int, u_long arg); | ||
99 | extern void release_tei(struct layer2 *); | ||
100 | extern int TEIInit(u_int *); | ||
101 | extern void TEIFree(void); | ||
102 | |||
103 | #define MAX_L2HEADER_LEN 4 | ||
104 | |||
105 | #define RR 0x01 | ||
106 | #define RNR 0x05 | ||
107 | #define REJ 0x09 | ||
108 | #define SABME 0x6f | ||
109 | #define SABM 0x2f | ||
110 | #define DM 0x0f | ||
111 | #define UI 0x03 | ||
112 | #define DISC 0x43 | ||
113 | #define UA 0x63 | ||
114 | #define FRMR 0x87 | ||
115 | #define XID 0xaf | ||
116 | |||
117 | #define CMD 0 | ||
118 | #define RSP 1 | ||
119 | |||
120 | #define LC_FLUSH_WAIT 1 | ||
121 | |||
122 | #define FLG_LAPB 0 | ||
123 | #define FLG_LAPD 1 | ||
124 | #define FLG_ORIG 2 | ||
125 | #define FLG_MOD128 3 | ||
126 | #define FLG_PEND_REL 4 | ||
127 | #define FLG_L3_INIT 5 | ||
128 | #define FLG_T200_RUN 6 | ||
129 | #define FLG_ACK_PEND 7 | ||
130 | #define FLG_REJEXC 8 | ||
131 | #define FLG_OWN_BUSY 9 | ||
132 | #define FLG_PEER_BUSY 10 | ||
133 | #define FLG_DCHAN_BUSY 11 | ||
134 | #define FLG_L1_ACTIV 12 | ||
135 | #define FLG_ESTAB_PEND 13 | ||
136 | #define FLG_PTP 14 | ||
137 | #define FLG_FIXED_TEI 15 | ||
138 | #define FLG_L2BLOCK 16 | ||
139 | #define FLG_L1_NOTREADY 17 | ||
140 | #define FLG_LAPD_NET 18 | ||
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c new file mode 100644 index 000000000000..4ba4cc364c9e --- /dev/null +++ b/drivers/isdn/mISDN/socket.c | |||
@@ -0,0 +1,781 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/mISDNif.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | static int *debug; | ||
22 | |||
23 | static struct proto mISDN_proto = { | ||
24 | .name = "misdn", | ||
25 | .owner = THIS_MODULE, | ||
26 | .obj_size = sizeof(struct mISDN_sock) | ||
27 | }; | ||
28 | |||
29 | #define _pms(sk) ((struct mISDN_sock *)sk) | ||
30 | |||
31 | static struct mISDN_sock_list data_sockets = { | ||
32 | .lock = __RW_LOCK_UNLOCKED(data_sockets.lock) | ||
33 | }; | ||
34 | |||
35 | static struct mISDN_sock_list base_sockets = { | ||
36 | .lock = __RW_LOCK_UNLOCKED(base_sockets.lock) | ||
37 | }; | ||
38 | |||
39 | #define L2_HEADER_LEN 4 | ||
40 | |||
41 | static inline struct sk_buff * | ||
42 | _l2_alloc_skb(unsigned int len, gfp_t gfp_mask) | ||
43 | { | ||
44 | struct sk_buff *skb; | ||
45 | |||
46 | skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask); | ||
47 | if (likely(skb)) | ||
48 | skb_reserve(skb, L2_HEADER_LEN); | ||
49 | return skb; | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk) | ||
54 | { | ||
55 | write_lock_bh(&l->lock); | ||
56 | sk_add_node(sk, &l->head); | ||
57 | write_unlock_bh(&l->lock); | ||
58 | } | ||
59 | |||
60 | static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk) | ||
61 | { | ||
62 | write_lock_bh(&l->lock); | ||
63 | sk_del_node_init(sk); | ||
64 | write_unlock_bh(&l->lock); | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
69 | { | ||
70 | struct mISDN_sock *msk; | ||
71 | int err; | ||
72 | |||
73 | msk = container_of(ch, struct mISDN_sock, ch); | ||
74 | if (*debug & DEBUG_SOCKET) | ||
75 | printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb); | ||
76 | if (msk->sk.sk_state == MISDN_CLOSED) | ||
77 | return -EUNATCH; | ||
78 | __net_timestamp(skb); | ||
79 | err = sock_queue_rcv_skb(&msk->sk, skb); | ||
80 | if (err) | ||
81 | printk(KERN_WARNING "%s: error %d\n", __func__, err); | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | static int | ||
86 | mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
87 | { | ||
88 | struct mISDN_sock *msk; | ||
89 | |||
90 | msk = container_of(ch, struct mISDN_sock, ch); | ||
91 | if (*debug & DEBUG_SOCKET) | ||
92 | printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg); | ||
93 | switch (cmd) { | ||
94 | case CLOSE_CHANNEL: | ||
95 | msk->sk.sk_state = MISDN_CLOSED; | ||
96 | break; | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static inline void | ||
102 | mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | ||
103 | { | ||
104 | struct timeval tv; | ||
105 | |||
106 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) { | ||
107 | skb_get_timestamp(skb, &tv); | ||
108 | put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
114 | struct msghdr *msg, size_t len, int flags) | ||
115 | { | ||
116 | struct sk_buff *skb; | ||
117 | struct sock *sk = sock->sk; | ||
118 | struct sockaddr_mISDN *maddr; | ||
119 | |||
120 | int copied, err; | ||
121 | |||
122 | if (*debug & DEBUG_SOCKET) | ||
123 | printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", | ||
124 | __func__, (int)len, flags, _pms(sk)->ch.nr, | ||
125 | sk->sk_protocol); | ||
126 | if (flags & (MSG_OOB)) | ||
127 | return -EOPNOTSUPP; | ||
128 | |||
129 | if (sk->sk_state == MISDN_CLOSED) | ||
130 | return 0; | ||
131 | |||
132 | skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); | ||
133 | if (!skb) | ||
134 | return err; | ||
135 | |||
136 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
137 | msg->msg_namelen = sizeof(struct sockaddr_mISDN); | ||
138 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
139 | maddr->family = AF_ISDN; | ||
140 | maddr->dev = _pms(sk)->dev->id; | ||
141 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
142 | (sk->sk_protocol == ISDN_P_LAPD_NT)) { | ||
143 | maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff; | ||
144 | maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff; | ||
145 | maddr->sapi = mISDN_HEAD_ID(skb) & 0xff; | ||
146 | } else { | ||
147 | maddr->channel = _pms(sk)->ch.nr; | ||
148 | maddr->sapi = _pms(sk)->ch.addr & 0xFF; | ||
149 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; | ||
150 | } | ||
151 | } else { | ||
152 | if (msg->msg_namelen) | ||
153 | printk(KERN_WARNING "%s: too small namelen %d\n", | ||
154 | __func__, msg->msg_namelen); | ||
155 | msg->msg_namelen = 0; | ||
156 | } | ||
157 | |||
158 | copied = skb->len + MISDN_HEADER_LEN; | ||
159 | if (len < copied) { | ||
160 | if (flags & MSG_PEEK) | ||
161 | atomic_dec(&skb->users); | ||
162 | else | ||
163 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
164 | return -ENOSPC; | ||
165 | } | ||
166 | memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), | ||
167 | MISDN_HEADER_LEN); | ||
168 | |||
169 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | ||
170 | |||
171 | mISDN_sock_cmsg(sk, msg, skb); | ||
172 | |||
173 | skb_free_datagram(sk, skb); | ||
174 | |||
175 | return err ? : copied; | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | ||
180 | struct msghdr *msg, size_t len) | ||
181 | { | ||
182 | struct sock *sk = sock->sk; | ||
183 | struct sk_buff *skb; | ||
184 | int err = -ENOMEM; | ||
185 | struct sockaddr_mISDN *maddr; | ||
186 | |||
187 | if (*debug & DEBUG_SOCKET) | ||
188 | printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", | ||
189 | __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, | ||
190 | sk->sk_protocol); | ||
191 | |||
192 | if (msg->msg_flags & MSG_OOB) | ||
193 | return -EOPNOTSUPP; | ||
194 | |||
195 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) | ||
196 | return -EINVAL; | ||
197 | |||
198 | if (len < MISDN_HEADER_LEN) | ||
199 | return -EINVAL; | ||
200 | |||
201 | if (sk->sk_state != MISDN_BOUND) | ||
202 | return -EBADFD; | ||
203 | |||
204 | lock_sock(sk); | ||
205 | |||
206 | skb = _l2_alloc_skb(len, GFP_KERNEL); | ||
207 | if (!skb) | ||
208 | goto done; | ||
209 | |||
210 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | ||
211 | err = -EFAULT; | ||
212 | goto drop; | ||
213 | } | ||
214 | |||
215 | memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); | ||
216 | skb_pull(skb, MISDN_HEADER_LEN); | ||
217 | |||
218 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
219 | /* if we have a address, we use it */ | ||
220 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
221 | mISDN_HEAD_ID(skb) = maddr->channel; | ||
222 | } else { /* use default for L2 messages */ | ||
223 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
224 | (sk->sk_protocol == ISDN_P_LAPD_NT)) | ||
225 | mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; | ||
226 | } | ||
227 | |||
228 | if (*debug & DEBUG_SOCKET) | ||
229 | printk(KERN_DEBUG "%s: ID:%x\n", | ||
230 | __func__, mISDN_HEAD_ID(skb)); | ||
231 | |||
232 | err = -ENODEV; | ||
233 | if (!_pms(sk)->ch.peer || | ||
234 | (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) | ||
235 | goto drop; | ||
236 | |||
237 | err = len; | ||
238 | |||
239 | done: | ||
240 | release_sock(sk); | ||
241 | return err; | ||
242 | |||
243 | drop: | ||
244 | kfree_skb(skb); | ||
245 | goto done; | ||
246 | } | ||
247 | |||
248 | static int | ||
249 | data_sock_release(struct socket *sock) | ||
250 | { | ||
251 | struct sock *sk = sock->sk; | ||
252 | |||
253 | if (*debug & DEBUG_SOCKET) | ||
254 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
255 | if (!sk) | ||
256 | return 0; | ||
257 | switch (sk->sk_protocol) { | ||
258 | case ISDN_P_TE_S0: | ||
259 | case ISDN_P_NT_S0: | ||
260 | case ISDN_P_TE_E1: | ||
261 | case ISDN_P_NT_E1: | ||
262 | if (sk->sk_state == MISDN_BOUND) | ||
263 | delete_channel(&_pms(sk)->ch); | ||
264 | else | ||
265 | mISDN_sock_unlink(&data_sockets, sk); | ||
266 | break; | ||
267 | case ISDN_P_LAPD_TE: | ||
268 | case ISDN_P_LAPD_NT: | ||
269 | case ISDN_P_B_RAW: | ||
270 | case ISDN_P_B_HDLC: | ||
271 | case ISDN_P_B_X75SLP: | ||
272 | case ISDN_P_B_L2DTMF: | ||
273 | case ISDN_P_B_L2DSP: | ||
274 | case ISDN_P_B_L2DSPHDLC: | ||
275 | delete_channel(&_pms(sk)->ch); | ||
276 | mISDN_sock_unlink(&data_sockets, sk); | ||
277 | break; | ||
278 | } | ||
279 | |||
280 | lock_sock(sk); | ||
281 | |||
282 | sock_orphan(sk); | ||
283 | skb_queue_purge(&sk->sk_receive_queue); | ||
284 | |||
285 | release_sock(sk); | ||
286 | sock_put(sk); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) | ||
293 | { | ||
294 | struct mISDN_ctrl_req cq; | ||
295 | int err = -EINVAL, val; | ||
296 | struct mISDNchannel *bchan, *next; | ||
297 | |||
298 | lock_sock(sk); | ||
299 | if (!_pms(sk)->dev) { | ||
300 | err = -ENODEV; | ||
301 | goto done; | ||
302 | } | ||
303 | switch (cmd) { | ||
304 | case IMCTRLREQ: | ||
305 | if (copy_from_user(&cq, p, sizeof(cq))) { | ||
306 | err = -EFAULT; | ||
307 | break; | ||
308 | } | ||
309 | if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { | ||
310 | list_for_each_entry_safe(bchan, next, | ||
311 | &_pms(sk)->dev->bchannels, list) { | ||
312 | if (bchan->nr == cq.channel) { | ||
313 | err = bchan->ctrl(bchan, | ||
314 | CONTROL_CHANNEL, &cq); | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | } else | ||
319 | err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, | ||
320 | CONTROL_CHANNEL, &cq); | ||
321 | if (err) | ||
322 | break; | ||
323 | if (copy_to_user(p, &cq, sizeof(cq))) | ||
324 | err = -EFAULT; | ||
325 | break; | ||
326 | case IMCLEAR_L2: | ||
327 | if (sk->sk_protocol != ISDN_P_LAPD_NT) { | ||
328 | err = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | if (get_user(val, (int __user *)p)) { | ||
332 | err = -EFAULT; | ||
333 | break; | ||
334 | } | ||
335 | err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, | ||
336 | CONTROL_CHANNEL, &val); | ||
337 | break; | ||
338 | default: | ||
339 | err = -EINVAL; | ||
340 | break; | ||
341 | } | ||
342 | done: | ||
343 | release_sock(sk); | ||
344 | return err; | ||
345 | } | ||
346 | |||
347 | static int | ||
348 | data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
349 | { | ||
350 | int err = 0, id; | ||
351 | struct sock *sk = sock->sk; | ||
352 | struct mISDNdevice *dev; | ||
353 | struct mISDNversion ver; | ||
354 | |||
355 | switch (cmd) { | ||
356 | case IMGETVERSION: | ||
357 | ver.major = MISDN_MAJOR_VERSION; | ||
358 | ver.minor = MISDN_MINOR_VERSION; | ||
359 | ver.release = MISDN_RELEASE; | ||
360 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
361 | err = -EFAULT; | ||
362 | break; | ||
363 | case IMGETCOUNT: | ||
364 | id = get_mdevice_count(); | ||
365 | if (put_user(id, (int __user *)arg)) | ||
366 | err = -EFAULT; | ||
367 | break; | ||
368 | case IMGETDEVINFO: | ||
369 | if (get_user(id, (int __user *)arg)) { | ||
370 | err = -EFAULT; | ||
371 | break; | ||
372 | } | ||
373 | dev = get_mdevice(id); | ||
374 | if (dev) { | ||
375 | struct mISDN_devinfo di; | ||
376 | |||
377 | di.id = dev->id; | ||
378 | di.Dprotocols = dev->Dprotocols; | ||
379 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
380 | di.protocol = dev->D.protocol; | ||
381 | memcpy(di.channelmap, dev->channelmap, | ||
382 | MISDN_CHMAP_SIZE * 4); | ||
383 | di.nrbchan = dev->nrbchan; | ||
384 | strcpy(di.name, dev->name); | ||
385 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
386 | err = -EFAULT; | ||
387 | } else | ||
388 | err = -ENODEV; | ||
389 | break; | ||
390 | default: | ||
391 | if (sk->sk_state == MISDN_BOUND) | ||
392 | err = data_sock_ioctl_bound(sk, cmd, | ||
393 | (void __user *)arg); | ||
394 | else | ||
395 | err = -ENOTCONN; | ||
396 | } | ||
397 | return err; | ||
398 | } | ||
399 | |||
400 | static int data_sock_setsockopt(struct socket *sock, int level, int optname, | ||
401 | char __user *optval, int len) | ||
402 | { | ||
403 | struct sock *sk = sock->sk; | ||
404 | int err = 0, opt = 0; | ||
405 | |||
406 | if (*debug & DEBUG_SOCKET) | ||
407 | printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock, | ||
408 | level, optname, optval, len); | ||
409 | |||
410 | lock_sock(sk); | ||
411 | |||
412 | switch (optname) { | ||
413 | case MISDN_TIME_STAMP: | ||
414 | if (get_user(opt, (int __user *)optval)) { | ||
415 | err = -EFAULT; | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | if (opt) | ||
420 | _pms(sk)->cmask |= MISDN_TIME_STAMP; | ||
421 | else | ||
422 | _pms(sk)->cmask &= ~MISDN_TIME_STAMP; | ||
423 | break; | ||
424 | default: | ||
425 | err = -ENOPROTOOPT; | ||
426 | break; | ||
427 | } | ||
428 | release_sock(sk); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | static int data_sock_getsockopt(struct socket *sock, int level, int optname, | ||
433 | char __user *optval, int __user *optlen) | ||
434 | { | ||
435 | struct sock *sk = sock->sk; | ||
436 | int len, opt; | ||
437 | |||
438 | if (get_user(len, optlen)) | ||
439 | return -EFAULT; | ||
440 | |||
441 | switch (optname) { | ||
442 | case MISDN_TIME_STAMP: | ||
443 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) | ||
444 | opt = 1; | ||
445 | else | ||
446 | opt = 0; | ||
447 | |||
448 | if (put_user(opt, optval)) | ||
449 | return -EFAULT; | ||
450 | break; | ||
451 | default: | ||
452 | return -ENOPROTOOPT; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int | ||
459 | data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
460 | { | ||
461 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
462 | struct sock *sk = sock->sk; | ||
463 | int err = 0; | ||
464 | |||
465 | if (*debug & DEBUG_SOCKET) | ||
466 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
467 | if (addr_len != sizeof(struct sockaddr_mISDN)) | ||
468 | return -EINVAL; | ||
469 | if (!maddr || maddr->family != AF_ISDN) | ||
470 | return -EINVAL; | ||
471 | |||
472 | lock_sock(sk); | ||
473 | |||
474 | if (_pms(sk)->dev) { | ||
475 | err = -EALREADY; | ||
476 | goto done; | ||
477 | } | ||
478 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
479 | if (!_pms(sk)->dev) { | ||
480 | err = -ENODEV; | ||
481 | goto done; | ||
482 | } | ||
483 | _pms(sk)->ch.send = mISDN_send; | ||
484 | _pms(sk)->ch.ctrl = mISDN_ctrl; | ||
485 | |||
486 | switch (sk->sk_protocol) { | ||
487 | case ISDN_P_TE_S0: | ||
488 | case ISDN_P_NT_S0: | ||
489 | case ISDN_P_TE_E1: | ||
490 | case ISDN_P_NT_E1: | ||
491 | mISDN_sock_unlink(&data_sockets, sk); | ||
492 | err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, | ||
493 | sk->sk_protocol, maddr); | ||
494 | if (err) | ||
495 | mISDN_sock_link(&data_sockets, sk); | ||
496 | break; | ||
497 | case ISDN_P_LAPD_TE: | ||
498 | case ISDN_P_LAPD_NT: | ||
499 | err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, | ||
500 | sk->sk_protocol, maddr); | ||
501 | break; | ||
502 | case ISDN_P_B_RAW: | ||
503 | case ISDN_P_B_HDLC: | ||
504 | case ISDN_P_B_X75SLP: | ||
505 | case ISDN_P_B_L2DTMF: | ||
506 | case ISDN_P_B_L2DSP: | ||
507 | case ISDN_P_B_L2DSPHDLC: | ||
508 | err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, | ||
509 | sk->sk_protocol, maddr); | ||
510 | break; | ||
511 | default: | ||
512 | err = -EPROTONOSUPPORT; | ||
513 | } | ||
514 | if (err) | ||
515 | goto done; | ||
516 | sk->sk_state = MISDN_BOUND; | ||
517 | _pms(sk)->ch.protocol = sk->sk_protocol; | ||
518 | |||
519 | done: | ||
520 | release_sock(sk); | ||
521 | return err; | ||
522 | } | ||
523 | |||
524 | static int | ||
525 | data_sock_getname(struct socket *sock, struct sockaddr *addr, | ||
526 | int *addr_len, int peer) | ||
527 | { | ||
528 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
529 | struct sock *sk = sock->sk; | ||
530 | |||
531 | if (!_pms(sk)->dev) | ||
532 | return -EBADFD; | ||
533 | |||
534 | lock_sock(sk); | ||
535 | |||
536 | *addr_len = sizeof(*maddr); | ||
537 | maddr->dev = _pms(sk)->dev->id; | ||
538 | maddr->channel = _pms(sk)->ch.nr; | ||
539 | maddr->sapi = _pms(sk)->ch.addr & 0xff; | ||
540 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff; | ||
541 | release_sock(sk); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static const struct proto_ops data_sock_ops = { | ||
546 | .family = PF_ISDN, | ||
547 | .owner = THIS_MODULE, | ||
548 | .release = data_sock_release, | ||
549 | .ioctl = data_sock_ioctl, | ||
550 | .bind = data_sock_bind, | ||
551 | .getname = data_sock_getname, | ||
552 | .sendmsg = mISDN_sock_sendmsg, | ||
553 | .recvmsg = mISDN_sock_recvmsg, | ||
554 | .poll = datagram_poll, | ||
555 | .listen = sock_no_listen, | ||
556 | .shutdown = sock_no_shutdown, | ||
557 | .setsockopt = data_sock_setsockopt, | ||
558 | .getsockopt = data_sock_getsockopt, | ||
559 | .connect = sock_no_connect, | ||
560 | .socketpair = sock_no_socketpair, | ||
561 | .accept = sock_no_accept, | ||
562 | .mmap = sock_no_mmap | ||
563 | }; | ||
564 | |||
565 | static int | ||
566 | data_sock_create(struct net *net, struct socket *sock, int protocol) | ||
567 | { | ||
568 | struct sock *sk; | ||
569 | |||
570 | if (sock->type != SOCK_DGRAM) | ||
571 | return -ESOCKTNOSUPPORT; | ||
572 | |||
573 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
574 | if (!sk) | ||
575 | return -ENOMEM; | ||
576 | |||
577 | sock_init_data(sock, sk); | ||
578 | |||
579 | sock->ops = &data_sock_ops; | ||
580 | sock->state = SS_UNCONNECTED; | ||
581 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
582 | |||
583 | sk->sk_protocol = protocol; | ||
584 | sk->sk_state = MISDN_OPEN; | ||
585 | mISDN_sock_link(&data_sockets, sk); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int | ||
591 | base_sock_release(struct socket *sock) | ||
592 | { | ||
593 | struct sock *sk = sock->sk; | ||
594 | |||
595 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
596 | if (!sk) | ||
597 | return 0; | ||
598 | |||
599 | mISDN_sock_unlink(&base_sockets, sk); | ||
600 | sock_orphan(sk); | ||
601 | sock_put(sk); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int | ||
607 | base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
608 | { | ||
609 | int err = 0, id; | ||
610 | struct mISDNdevice *dev; | ||
611 | struct mISDNversion ver; | ||
612 | |||
613 | switch (cmd) { | ||
614 | case IMGETVERSION: | ||
615 | ver.major = MISDN_MAJOR_VERSION; | ||
616 | ver.minor = MISDN_MINOR_VERSION; | ||
617 | ver.release = MISDN_RELEASE; | ||
618 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
619 | err = -EFAULT; | ||
620 | break; | ||
621 | case IMGETCOUNT: | ||
622 | id = get_mdevice_count(); | ||
623 | if (put_user(id, (int __user *)arg)) | ||
624 | err = -EFAULT; | ||
625 | break; | ||
626 | case IMGETDEVINFO: | ||
627 | if (get_user(id, (int __user *)arg)) { | ||
628 | err = -EFAULT; | ||
629 | break; | ||
630 | } | ||
631 | dev = get_mdevice(id); | ||
632 | if (dev) { | ||
633 | struct mISDN_devinfo di; | ||
634 | |||
635 | di.id = dev->id; | ||
636 | di.Dprotocols = dev->Dprotocols; | ||
637 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
638 | di.protocol = dev->D.protocol; | ||
639 | memcpy(di.channelmap, dev->channelmap, | ||
640 | MISDN_CHMAP_SIZE * 4); | ||
641 | di.nrbchan = dev->nrbchan; | ||
642 | strcpy(di.name, dev->name); | ||
643 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
644 | err = -EFAULT; | ||
645 | } else | ||
646 | err = -ENODEV; | ||
647 | break; | ||
648 | default: | ||
649 | err = -EINVAL; | ||
650 | } | ||
651 | return err; | ||
652 | } | ||
653 | |||
654 | static int | ||
655 | base_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
656 | { | ||
657 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
658 | struct sock *sk = sock->sk; | ||
659 | int err = 0; | ||
660 | |||
661 | if (!maddr || maddr->family != AF_ISDN) | ||
662 | return -EINVAL; | ||
663 | |||
664 | lock_sock(sk); | ||
665 | |||
666 | if (_pms(sk)->dev) { | ||
667 | err = -EALREADY; | ||
668 | goto done; | ||
669 | } | ||
670 | |||
671 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
672 | if (!_pms(sk)->dev) { | ||
673 | err = -ENODEV; | ||
674 | goto done; | ||
675 | } | ||
676 | sk->sk_state = MISDN_BOUND; | ||
677 | |||
678 | done: | ||
679 | release_sock(sk); | ||
680 | return err; | ||
681 | } | ||
682 | |||
683 | static const struct proto_ops base_sock_ops = { | ||
684 | .family = PF_ISDN, | ||
685 | .owner = THIS_MODULE, | ||
686 | .release = base_sock_release, | ||
687 | .ioctl = base_sock_ioctl, | ||
688 | .bind = base_sock_bind, | ||
689 | .getname = sock_no_getname, | ||
690 | .sendmsg = sock_no_sendmsg, | ||
691 | .recvmsg = sock_no_recvmsg, | ||
692 | .poll = sock_no_poll, | ||
693 | .listen = sock_no_listen, | ||
694 | .shutdown = sock_no_shutdown, | ||
695 | .setsockopt = sock_no_setsockopt, | ||
696 | .getsockopt = sock_no_getsockopt, | ||
697 | .connect = sock_no_connect, | ||
698 | .socketpair = sock_no_socketpair, | ||
699 | .accept = sock_no_accept, | ||
700 | .mmap = sock_no_mmap | ||
701 | }; | ||
702 | |||
703 | |||
704 | static int | ||
705 | base_sock_create(struct net *net, struct socket *sock, int protocol) | ||
706 | { | ||
707 | struct sock *sk; | ||
708 | |||
709 | if (sock->type != SOCK_RAW) | ||
710 | return -ESOCKTNOSUPPORT; | ||
711 | |||
712 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
713 | if (!sk) | ||
714 | return -ENOMEM; | ||
715 | |||
716 | sock_init_data(sock, sk); | ||
717 | sock->ops = &base_sock_ops; | ||
718 | sock->state = SS_UNCONNECTED; | ||
719 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
720 | sk->sk_protocol = protocol; | ||
721 | sk->sk_state = MISDN_OPEN; | ||
722 | mISDN_sock_link(&base_sockets, sk); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int | ||
728 | mISDN_sock_create(struct net *net, struct socket *sock, int proto) | ||
729 | { | ||
730 | int err = -EPROTONOSUPPORT; | ||
731 | |||
732 | switch (proto) { | ||
733 | case ISDN_P_BASE: | ||
734 | err = base_sock_create(net, sock, proto); | ||
735 | break; | ||
736 | case ISDN_P_TE_S0: | ||
737 | case ISDN_P_NT_S0: | ||
738 | case ISDN_P_TE_E1: | ||
739 | case ISDN_P_NT_E1: | ||
740 | case ISDN_P_LAPD_TE: | ||
741 | case ISDN_P_LAPD_NT: | ||
742 | case ISDN_P_B_RAW: | ||
743 | case ISDN_P_B_HDLC: | ||
744 | case ISDN_P_B_X75SLP: | ||
745 | case ISDN_P_B_L2DTMF: | ||
746 | case ISDN_P_B_L2DSP: | ||
747 | case ISDN_P_B_L2DSPHDLC: | ||
748 | err = data_sock_create(net, sock, proto); | ||
749 | break; | ||
750 | default: | ||
751 | return err; | ||
752 | } | ||
753 | |||
754 | return err; | ||
755 | } | ||
756 | |||
757 | static struct | ||
758 | net_proto_family mISDN_sock_family_ops = { | ||
759 | .owner = THIS_MODULE, | ||
760 | .family = PF_ISDN, | ||
761 | .create = mISDN_sock_create, | ||
762 | }; | ||
763 | |||
764 | int | ||
765 | misdn_sock_init(u_int *deb) | ||
766 | { | ||
767 | int err; | ||
768 | |||
769 | debug = deb; | ||
770 | err = sock_register(&mISDN_sock_family_ops); | ||
771 | if (err) | ||
772 | printk(KERN_ERR "%s: error(%d)\n", __func__, err); | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | void | ||
777 | misdn_sock_cleanup(void) | ||
778 | { | ||
779 | sock_unregister(PF_ISDN); | ||
780 | } | ||
781 | |||
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c new file mode 100644 index 000000000000..54cfddcc4784 --- /dev/null +++ b/drivers/isdn/mISDN/stack.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/mISDNif.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include "core.h" | ||
21 | |||
22 | static u_int *debug; | ||
23 | |||
24 | static inline void | ||
25 | _queue_message(struct mISDNstack *st, struct sk_buff *skb) | ||
26 | { | ||
27 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
28 | |||
29 | if (*debug & DEBUG_QUEUE_FUNC) | ||
30 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
31 | __func__, hh->prim, hh->id, skb); | ||
32 | skb_queue_tail(&st->msgq, skb); | ||
33 | if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
34 | test_and_set_bit(mISDN_STACK_WORK, &st->status); | ||
35 | wake_up_interruptible(&st->workq); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | int | ||
40 | mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) | ||
41 | { | ||
42 | _queue_message(ch->st, skb); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static struct mISDNchannel * | ||
47 | get_channel4id(struct mISDNstack *st, u_int id) | ||
48 | { | ||
49 | struct mISDNchannel *ch; | ||
50 | |||
51 | mutex_lock(&st->lmutex); | ||
52 | list_for_each_entry(ch, &st->layer2, list) { | ||
53 | if (id == ch->nr) | ||
54 | goto unlock; | ||
55 | } | ||
56 | ch = NULL; | ||
57 | unlock: | ||
58 | mutex_unlock(&st->lmutex); | ||
59 | return ch; | ||
60 | } | ||
61 | |||
62 | static void | ||
63 | send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) | ||
64 | { | ||
65 | struct hlist_node *node; | ||
66 | struct sock *sk; | ||
67 | struct sk_buff *cskb = NULL; | ||
68 | |||
69 | read_lock(&sl->lock); | ||
70 | sk_for_each(sk, node, &sl->head) { | ||
71 | if (sk->sk_state != MISDN_BOUND) | ||
72 | continue; | ||
73 | if (!cskb) | ||
74 | cskb = skb_copy(skb, GFP_KERNEL); | ||
75 | if (!cskb) { | ||
76 | printk(KERN_WARNING "%s no skb\n", __func__); | ||
77 | break; | ||
78 | } | ||
79 | if (!sock_queue_rcv_skb(sk, cskb)) | ||
80 | cskb = NULL; | ||
81 | } | ||
82 | read_unlock(&sl->lock); | ||
83 | if (cskb) | ||
84 | dev_kfree_skb(cskb); | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | send_layer2(struct mISDNstack *st, struct sk_buff *skb) | ||
89 | { | ||
90 | struct sk_buff *cskb; | ||
91 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
92 | struct mISDNchannel *ch; | ||
93 | int ret; | ||
94 | |||
95 | if (!st) | ||
96 | return; | ||
97 | mutex_lock(&st->lmutex); | ||
98 | if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */ | ||
99 | list_for_each_entry(ch, &st->layer2, list) { | ||
100 | if (list_is_last(&ch->list, &st->layer2)) { | ||
101 | cskb = skb; | ||
102 | skb = NULL; | ||
103 | } else { | ||
104 | cskb = skb_copy(skb, GFP_KERNEL); | ||
105 | } | ||
106 | if (cskb) { | ||
107 | ret = ch->send(ch, cskb); | ||
108 | if (ret) { | ||
109 | if (*debug & DEBUG_SEND_ERR) | ||
110 | printk(KERN_DEBUG | ||
111 | "%s ch%d prim(%x) addr(%x)" | ||
112 | " err %d\n", | ||
113 | __func__, ch->nr, | ||
114 | hh->prim, ch->addr, ret); | ||
115 | dev_kfree_skb(cskb); | ||
116 | } | ||
117 | } else { | ||
118 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
119 | __func__, ch->nr, ch->addr); | ||
120 | goto out; | ||
121 | } | ||
122 | } | ||
123 | } else { | ||
124 | list_for_each_entry(ch, &st->layer2, list) { | ||
125 | if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) { | ||
126 | ret = ch->send(ch, skb); | ||
127 | if (!ret) | ||
128 | skb = NULL; | ||
129 | goto out; | ||
130 | } | ||
131 | } | ||
132 | ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb); | ||
133 | if (!ret) | ||
134 | skb = NULL; | ||
135 | else if (*debug & DEBUG_SEND_ERR) | ||
136 | printk(KERN_DEBUG | ||
137 | "%s ch%d mgr prim(%x) addr(%x) err %d\n", | ||
138 | __func__, ch->nr, hh->prim, ch->addr, ret); | ||
139 | } | ||
140 | out: | ||
141 | mutex_unlock(&st->lmutex); | ||
142 | if (skb) | ||
143 | dev_kfree_skb(skb); | ||
144 | } | ||
145 | |||
146 | static inline int | ||
147 | send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) | ||
148 | { | ||
149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
150 | struct mISDNchannel *ch; | ||
151 | int lm; | ||
152 | |||
153 | lm = hh->prim & MISDN_LAYERMASK; | ||
154 | if (*debug & DEBUG_QUEUE_FUNC) | ||
155 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
156 | __func__, hh->prim, hh->id, skb); | ||
157 | if (lm == 0x1) { | ||
158 | if (!hlist_empty(&st->l1sock.head)) { | ||
159 | __net_timestamp(skb); | ||
160 | send_socklist(&st->l1sock, skb); | ||
161 | } | ||
162 | return st->layer1->send(st->layer1, skb); | ||
163 | } else if (lm == 0x2) { | ||
164 | if (!hlist_empty(&st->l1sock.head)) | ||
165 | send_socklist(&st->l1sock, skb); | ||
166 | send_layer2(st, skb); | ||
167 | return 0; | ||
168 | } else if (lm == 0x4) { | ||
169 | ch = get_channel4id(st, hh->id); | ||
170 | if (ch) | ||
171 | return ch->send(ch, skb); | ||
172 | else | ||
173 | printk(KERN_WARNING | ||
174 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
175 | __func__, st->dev->name, hh->prim, hh->id); | ||
176 | } else if (lm == 0x8) { | ||
177 | WARN_ON(lm == 0x8); | ||
178 | ch = get_channel4id(st, hh->id); | ||
179 | if (ch) | ||
180 | return ch->send(ch, skb); | ||
181 | else | ||
182 | printk(KERN_WARNING | ||
183 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
184 | __func__, st->dev->name, hh->prim, hh->id); | ||
185 | } else { | ||
186 | /* broadcast not handled yet */ | ||
187 | printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", | ||
188 | __func__, st->dev->name, hh->prim); | ||
189 | } | ||
190 | return -ESRCH; | ||
191 | } | ||
192 | |||
193 | static void | ||
194 | do_clear_stack(struct mISDNstack *st) | ||
195 | { | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | mISDNStackd(void *data) | ||
200 | { | ||
201 | struct mISDNstack *st = data; | ||
202 | int err = 0; | ||
203 | |||
204 | #ifdef CONFIG_SMP | ||
205 | lock_kernel(); | ||
206 | #endif | ||
207 | sigfillset(¤t->blocked); | ||
208 | #ifdef CONFIG_SMP | ||
209 | unlock_kernel(); | ||
210 | #endif | ||
211 | if (*debug & DEBUG_MSG_THREAD) | ||
212 | printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); | ||
213 | |||
214 | if (st->notify != NULL) { | ||
215 | complete(st->notify); | ||
216 | st->notify = NULL; | ||
217 | } | ||
218 | |||
219 | for (;;) { | ||
220 | struct sk_buff *skb; | ||
221 | |||
222 | if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
223 | test_and_clear_bit(mISDN_STACK_WORK, &st->status); | ||
224 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
225 | } else | ||
226 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
227 | while (test_bit(mISDN_STACK_WORK, &st->status)) { | ||
228 | skb = skb_dequeue(&st->msgq); | ||
229 | if (!skb) { | ||
230 | test_and_clear_bit(mISDN_STACK_WORK, | ||
231 | &st->status); | ||
232 | /* test if a race happens */ | ||
233 | skb = skb_dequeue(&st->msgq); | ||
234 | if (!skb) | ||
235 | continue; | ||
236 | test_and_set_bit(mISDN_STACK_WORK, | ||
237 | &st->status); | ||
238 | } | ||
239 | #ifdef MISDN_MSG_STATS | ||
240 | st->msg_cnt++; | ||
241 | #endif | ||
242 | err = send_msg_to_layer(st, skb); | ||
243 | if (unlikely(err)) { | ||
244 | if (*debug & DEBUG_SEND_ERR) | ||
245 | printk(KERN_DEBUG | ||
246 | "%s: %s prim(%x) id(%x) " | ||
247 | "send call(%d)\n", | ||
248 | __func__, st->dev->name, | ||
249 | mISDN_HEAD_PRIM(skb), | ||
250 | mISDN_HEAD_ID(skb), err); | ||
251 | dev_kfree_skb(skb); | ||
252 | continue; | ||
253 | } | ||
254 | if (unlikely(test_bit(mISDN_STACK_STOPPED, | ||
255 | &st->status))) { | ||
256 | test_and_clear_bit(mISDN_STACK_WORK, | ||
257 | &st->status); | ||
258 | test_and_clear_bit(mISDN_STACK_RUNNING, | ||
259 | &st->status); | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | if (test_bit(mISDN_STACK_CLEARING, &st->status)) { | ||
264 | test_and_set_bit(mISDN_STACK_STOPPED, &st->status); | ||
265 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
266 | do_clear_stack(st); | ||
267 | test_and_clear_bit(mISDN_STACK_CLEARING, &st->status); | ||
268 | test_and_set_bit(mISDN_STACK_RESTART, &st->status); | ||
269 | } | ||
270 | if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) { | ||
271 | test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); | ||
272 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
273 | if (!skb_queue_empty(&st->msgq)) | ||
274 | test_and_set_bit(mISDN_STACK_WORK, | ||
275 | &st->status); | ||
276 | } | ||
277 | if (test_bit(mISDN_STACK_ABORT, &st->status)) | ||
278 | break; | ||
279 | if (st->notify != NULL) { | ||
280 | complete(st->notify); | ||
281 | st->notify = NULL; | ||
282 | } | ||
283 | #ifdef MISDN_MSG_STATS | ||
284 | st->sleep_cnt++; | ||
285 | #endif | ||
286 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
287 | wait_event_interruptible(st->workq, (st->status & | ||
288 | mISDN_STACK_ACTION_MASK)); | ||
289 | if (*debug & DEBUG_MSG_THREAD) | ||
290 | printk(KERN_DEBUG "%s: %s wake status %08lx\n", | ||
291 | __func__, st->dev->name, st->status); | ||
292 | test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); | ||
293 | |||
294 | test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); | ||
295 | |||
296 | if (test_bit(mISDN_STACK_STOPPED, &st->status)) { | ||
297 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
298 | #ifdef MISDN_MSG_STATS | ||
299 | st->stopped_cnt++; | ||
300 | #endif | ||
301 | } | ||
302 | } | ||
303 | #ifdef MISDN_MSG_STATS | ||
304 | printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " | ||
305 | "msg %d sleep %d stopped\n", | ||
306 | st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); | ||
307 | printk(KERN_DEBUG | ||
308 | "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", | ||
309 | st->dev->name, st->thread->utime, st->thread->stime); | ||
310 | printk(KERN_DEBUG | ||
311 | "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", | ||
312 | st->dev->name, st->thread->nvcsw, st->thread->nivcsw); | ||
313 | printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", | ||
314 | st->dev->name); | ||
315 | #endif | ||
316 | test_and_set_bit(mISDN_STACK_KILLED, &st->status); | ||
317 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
318 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
319 | test_and_clear_bit(mISDN_STACK_ABORT, &st->status); | ||
320 | skb_queue_purge(&st->msgq); | ||
321 | st->thread = NULL; | ||
322 | if (st->notify != NULL) { | ||
323 | complete(st->notify); | ||
324 | st->notify = NULL; | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int | ||
330 | l1_receive(struct mISDNchannel *ch, struct sk_buff *skb) | ||
331 | { | ||
332 | if (!ch->st) | ||
333 | return -ENODEV; | ||
334 | __net_timestamp(skb); | ||
335 | _queue_message(ch->st, skb); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | void | ||
340 | set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei) | ||
341 | { | ||
342 | ch->addr = sapi | (tei << 8); | ||
343 | } | ||
344 | |||
345 | void | ||
346 | __add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
347 | { | ||
348 | list_add_tail(&ch->list, &st->layer2); | ||
349 | } | ||
350 | |||
351 | void | ||
352 | add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
353 | { | ||
354 | mutex_lock(&st->lmutex); | ||
355 | __add_layer2(ch, st); | ||
356 | mutex_unlock(&st->lmutex); | ||
357 | } | ||
358 | |||
359 | static int | ||
360 | st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
361 | { | ||
362 | if (!ch->st || ch->st->layer1) | ||
363 | return -EINVAL; | ||
364 | return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); | ||
365 | } | ||
366 | |||
367 | int | ||
368 | create_stack(struct mISDNdevice *dev) | ||
369 | { | ||
370 | struct mISDNstack *newst; | ||
371 | int err; | ||
372 | DECLARE_COMPLETION_ONSTACK(done); | ||
373 | |||
374 | newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL); | ||
375 | if (!newst) { | ||
376 | printk(KERN_ERR "kmalloc mISDN_stack failed\n"); | ||
377 | return -ENOMEM; | ||
378 | } | ||
379 | newst->dev = dev; | ||
380 | INIT_LIST_HEAD(&newst->layer2); | ||
381 | INIT_HLIST_HEAD(&newst->l1sock.head); | ||
382 | rwlock_init(&newst->l1sock.lock); | ||
383 | init_waitqueue_head(&newst->workq); | ||
384 | skb_queue_head_init(&newst->msgq); | ||
385 | mutex_init(&newst->lmutex); | ||
386 | dev->D.st = newst; | ||
387 | err = create_teimanager(dev); | ||
388 | if (err) { | ||
389 | printk(KERN_ERR "kmalloc teimanager failed\n"); | ||
390 | kfree(newst); | ||
391 | return err; | ||
392 | } | ||
393 | dev->teimgr->peer = &newst->own; | ||
394 | dev->teimgr->recv = mISDN_queue_message; | ||
395 | dev->teimgr->st = newst; | ||
396 | newst->layer1 = &dev->D; | ||
397 | dev->D.recv = l1_receive; | ||
398 | dev->D.peer = &newst->own; | ||
399 | newst->own.st = newst; | ||
400 | newst->own.ctrl = st_own_ctrl; | ||
401 | newst->own.send = mISDN_queue_message; | ||
402 | newst->own.recv = mISDN_queue_message; | ||
403 | if (*debug & DEBUG_CORE_FUNC) | ||
404 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); | ||
405 | newst->notify = &done; | ||
406 | newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", | ||
407 | newst->dev->name); | ||
408 | if (IS_ERR(newst->thread)) { | ||
409 | err = PTR_ERR(newst->thread); | ||
410 | printk(KERN_ERR | ||
411 | "mISDN:cannot create kernel thread for %s (%d)\n", | ||
412 | newst->dev->name, err); | ||
413 | delete_teimanager(dev->teimgr); | ||
414 | kfree(newst); | ||
415 | } else | ||
416 | wait_for_completion(&done); | ||
417 | return err; | ||
418 | } | ||
419 | |||
420 | int | ||
421 | connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
422 | u_int protocol, struct sockaddr_mISDN *adr) | ||
423 | { | ||
424 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
425 | struct channel_req rq; | ||
426 | int err; | ||
427 | |||
428 | |||
429 | if (*debug & DEBUG_CORE_FUNC) | ||
430 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
431 | __func__, dev->name, protocol, adr->dev, adr->channel, | ||
432 | adr->sapi, adr->tei); | ||
433 | switch (protocol) { | ||
434 | case ISDN_P_NT_S0: | ||
435 | case ISDN_P_NT_E1: | ||
436 | case ISDN_P_TE_S0: | ||
437 | case ISDN_P_TE_E1: | ||
438 | #ifdef PROTOCOL_CHECK | ||
439 | /* this should be enhanced */ | ||
440 | if (!list_empty(&dev->D.st->layer2) | ||
441 | && dev->D.protocol != protocol) | ||
442 | return -EBUSY; | ||
443 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
444 | && dev->D.protocol != protocol) | ||
445 | return -EBUSY; | ||
446 | #endif | ||
447 | ch->recv = mISDN_queue_message; | ||
448 | ch->peer = &dev->D.st->own; | ||
449 | ch->st = dev->D.st; | ||
450 | rq.protocol = protocol; | ||
451 | rq.adr.channel = 0; | ||
452 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
453 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
454 | if (err) | ||
455 | return err; | ||
456 | write_lock_bh(&dev->D.st->l1sock.lock); | ||
457 | sk_add_node(&msk->sk, &dev->D.st->l1sock.head); | ||
458 | write_unlock_bh(&dev->D.st->l1sock.lock); | ||
459 | break; | ||
460 | default: | ||
461 | return -ENOPROTOOPT; | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | int | ||
467 | connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
468 | u_int protocol, struct sockaddr_mISDN *adr) | ||
469 | { | ||
470 | struct channel_req rq, rq2; | ||
471 | int pmask, err; | ||
472 | struct Bprotocol *bp; | ||
473 | |||
474 | if (*debug & DEBUG_CORE_FUNC) | ||
475 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
476 | __func__, dev->name, protocol, | ||
477 | adr->dev, adr->channel, adr->sapi, | ||
478 | adr->tei); | ||
479 | ch->st = dev->D.st; | ||
480 | pmask = 1 << (protocol & ISDN_P_B_MASK); | ||
481 | if (pmask & dev->Bprotocols) { | ||
482 | rq.protocol = protocol; | ||
483 | rq.adr = *adr; | ||
484 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
485 | if (err) | ||
486 | return err; | ||
487 | ch->recv = rq.ch->send; | ||
488 | ch->peer = rq.ch; | ||
489 | rq.ch->recv = ch->send; | ||
490 | rq.ch->peer = ch; | ||
491 | rq.ch->st = dev->D.st; | ||
492 | } else { | ||
493 | bp = get_Bprotocol4mask(pmask); | ||
494 | if (!bp) | ||
495 | return -ENOPROTOOPT; | ||
496 | rq2.protocol = protocol; | ||
497 | rq2.adr = *adr; | ||
498 | rq2.ch = ch; | ||
499 | err = bp->create(&rq2); | ||
500 | if (err) | ||
501 | return err; | ||
502 | ch->recv = rq2.ch->send; | ||
503 | ch->peer = rq2.ch; | ||
504 | rq2.ch->st = dev->D.st; | ||
505 | rq.protocol = rq2.protocol; | ||
506 | rq.adr = *adr; | ||
507 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
508 | if (err) { | ||
509 | rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL); | ||
510 | return err; | ||
511 | } | ||
512 | rq2.ch->recv = rq.ch->send; | ||
513 | rq2.ch->peer = rq.ch; | ||
514 | rq.ch->recv = rq2.ch->send; | ||
515 | rq.ch->peer = rq2.ch; | ||
516 | rq.ch->st = dev->D.st; | ||
517 | } | ||
518 | ch->protocol = protocol; | ||
519 | ch->nr = rq.ch->nr; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | int | ||
524 | create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
525 | u_int protocol, struct sockaddr_mISDN *adr) | ||
526 | { | ||
527 | struct channel_req rq; | ||
528 | int err; | ||
529 | |||
530 | if (*debug & DEBUG_CORE_FUNC) | ||
531 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
532 | __func__, dev->name, protocol, | ||
533 | adr->dev, adr->channel, adr->sapi, | ||
534 | adr->tei); | ||
535 | rq.protocol = ISDN_P_TE_S0; | ||
536 | if (dev->Dprotocols & (1 << ISDN_P_TE_E1)) | ||
537 | rq.protocol = ISDN_P_TE_E1; | ||
538 | switch (protocol) { | ||
539 | case ISDN_P_LAPD_NT: | ||
540 | rq.protocol = ISDN_P_NT_S0; | ||
541 | if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) | ||
542 | rq.protocol = ISDN_P_NT_E1; | ||
543 | case ISDN_P_LAPD_TE: | ||
544 | #ifdef PROTOCOL_CHECK | ||
545 | /* this should be enhanced */ | ||
546 | if (!list_empty(&dev->D.st->layer2) | ||
547 | && dev->D.protocol != protocol) | ||
548 | return -EBUSY; | ||
549 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
550 | && dev->D.protocol != protocol) | ||
551 | return -EBUSY; | ||
552 | #endif | ||
553 | ch->recv = mISDN_queue_message; | ||
554 | ch->peer = &dev->D.st->own; | ||
555 | ch->st = dev->D.st; | ||
556 | rq.adr.channel = 0; | ||
557 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
558 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
559 | if (err) | ||
560 | break; | ||
561 | rq.protocol = protocol; | ||
562 | rq.adr = *adr; | ||
563 | rq.ch = ch; | ||
564 | err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq); | ||
565 | printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err); | ||
566 | if (!err) { | ||
567 | if ((protocol == ISDN_P_LAPD_NT) && !rq.ch) | ||
568 | break; | ||
569 | add_layer2(rq.ch, dev->D.st); | ||
570 | rq.ch->recv = mISDN_queue_message; | ||
571 | rq.ch->peer = &dev->D.st->own; | ||
572 | rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */ | ||
573 | } | ||
574 | break; | ||
575 | default: | ||
576 | err = -EPROTONOSUPPORT; | ||
577 | } | ||
578 | return err; | ||
579 | } | ||
580 | |||
581 | void | ||
582 | delete_channel(struct mISDNchannel *ch) | ||
583 | { | ||
584 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
585 | struct mISDNchannel *pch; | ||
586 | |||
587 | if (!ch->st) { | ||
588 | printk(KERN_WARNING "%s: no stack\n", __func__); | ||
589 | return; | ||
590 | } | ||
591 | if (*debug & DEBUG_CORE_FUNC) | ||
592 | printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, | ||
593 | ch->st->dev->name, ch->protocol); | ||
594 | if (ch->protocol >= ISDN_P_B_START) { | ||
595 | if (ch->peer) { | ||
596 | ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); | ||
597 | ch->peer = NULL; | ||
598 | } | ||
599 | return; | ||
600 | } | ||
601 | switch (ch->protocol) { | ||
602 | case ISDN_P_NT_S0: | ||
603 | case ISDN_P_TE_S0: | ||
604 | case ISDN_P_NT_E1: | ||
605 | case ISDN_P_TE_E1: | ||
606 | write_lock_bh(&ch->st->l1sock.lock); | ||
607 | sk_del_node_init(&msk->sk); | ||
608 | write_unlock_bh(&ch->st->l1sock.lock); | ||
609 | ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL); | ||
610 | break; | ||
611 | case ISDN_P_LAPD_TE: | ||
612 | pch = get_channel4id(ch->st, ch->nr); | ||
613 | if (pch) { | ||
614 | mutex_lock(&ch->st->lmutex); | ||
615 | list_del(&pch->list); | ||
616 | mutex_unlock(&ch->st->lmutex); | ||
617 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
618 | pch = ch->st->dev->teimgr; | ||
619 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
620 | } else | ||
621 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
622 | __func__); | ||
623 | break; | ||
624 | case ISDN_P_LAPD_NT: | ||
625 | pch = ch->st->dev->teimgr; | ||
626 | if (pch) { | ||
627 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
628 | } else | ||
629 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
630 | __func__); | ||
631 | break; | ||
632 | default: | ||
633 | break; | ||
634 | } | ||
635 | return; | ||
636 | } | ||
637 | |||
638 | void | ||
639 | delete_stack(struct mISDNdevice *dev) | ||
640 | { | ||
641 | struct mISDNstack *st = dev->D.st; | ||
642 | DECLARE_COMPLETION_ONSTACK(done); | ||
643 | |||
644 | if (*debug & DEBUG_CORE_FUNC) | ||
645 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, | ||
646 | st->dev->name); | ||
647 | if (dev->teimgr) | ||
648 | delete_teimanager(dev->teimgr); | ||
649 | if (st->thread) { | ||
650 | if (st->notify) { | ||
651 | printk(KERN_WARNING "%s: notifier in use\n", | ||
652 | __func__); | ||
653 | complete(st->notify); | ||
654 | } | ||
655 | st->notify = &done; | ||
656 | test_and_set_bit(mISDN_STACK_ABORT, &st->status); | ||
657 | test_and_set_bit(mISDN_STACK_WAKEUP, &st->status); | ||
658 | wake_up_interruptible(&st->workq); | ||
659 | wait_for_completion(&done); | ||
660 | } | ||
661 | if (!list_empty(&st->layer2)) | ||
662 | printk(KERN_WARNING "%s: layer2 list not empty\n", | ||
663 | __func__); | ||
664 | if (!hlist_empty(&st->l1sock.head)) | ||
665 | printk(KERN_WARNING "%s: layer1 list not empty\n", | ||
666 | __func__); | ||
667 | kfree(st); | ||
668 | } | ||
669 | |||
670 | void | ||
671 | mISDN_initstack(u_int *dp) | ||
672 | { | ||
673 | debug = dp; | ||
674 | } | ||
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c new file mode 100644 index 000000000000..56a76a0ffddd --- /dev/null +++ b/drivers/isdn/mISDN/tei.c | |||
@@ -0,0 +1,1340 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | #include "layer2.h" | ||
18 | #include <linux/random.h> | ||
19 | #include "core.h" | ||
20 | |||
21 | #define ID_REQUEST 1 | ||
22 | #define ID_ASSIGNED 2 | ||
23 | #define ID_DENIED 3 | ||
24 | #define ID_CHK_REQ 4 | ||
25 | #define ID_CHK_RES 5 | ||
26 | #define ID_REMOVE 6 | ||
27 | #define ID_VERIFY 7 | ||
28 | |||
29 | #define TEI_ENTITY_ID 0xf | ||
30 | |||
31 | #define MGR_PH_ACTIVE 16 | ||
32 | #define MGR_PH_NOTREADY 17 | ||
33 | |||
34 | #define DATIMER_VAL 10000 | ||
35 | |||
36 | static u_int *debug; | ||
37 | |||
38 | static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; | ||
39 | static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; | ||
40 | static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; | ||
41 | |||
42 | enum { | ||
43 | ST_L1_DEACT, | ||
44 | ST_L1_DEACT_PENDING, | ||
45 | ST_L1_ACTIV, | ||
46 | }; | ||
47 | #define DEACT_STATE_COUNT (ST_L1_ACTIV+1) | ||
48 | |||
49 | static char *strDeactState[] = | ||
50 | { | ||
51 | "ST_L1_DEACT", | ||
52 | "ST_L1_DEACT_PENDING", | ||
53 | "ST_L1_ACTIV", | ||
54 | }; | ||
55 | |||
56 | enum { | ||
57 | EV_ACTIVATE, | ||
58 | EV_ACTIVATE_IND, | ||
59 | EV_DEACTIVATE, | ||
60 | EV_DEACTIVATE_IND, | ||
61 | EV_UI, | ||
62 | EV_DATIMER, | ||
63 | }; | ||
64 | |||
65 | #define DEACT_EVENT_COUNT (EV_DATIMER+1) | ||
66 | |||
67 | static char *strDeactEvent[] = | ||
68 | { | ||
69 | "EV_ACTIVATE", | ||
70 | "EV_ACTIVATE_IND", | ||
71 | "EV_DEACTIVATE", | ||
72 | "EV_DEACTIVATE_IND", | ||
73 | "EV_UI", | ||
74 | "EV_DATIMER", | ||
75 | }; | ||
76 | |||
77 | static void | ||
78 | da_debug(struct FsmInst *fi, char *fmt, ...) | ||
79 | { | ||
80 | struct manager *mgr = fi->userdata; | ||
81 | va_list va; | ||
82 | |||
83 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
84 | return; | ||
85 | va_start(va, fmt); | ||
86 | printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id); | ||
87 | vprintk(fmt, va); | ||
88 | printk("\n"); | ||
89 | va_end(va); | ||
90 | } | ||
91 | |||
92 | static void | ||
93 | da_activate(struct FsmInst *fi, int event, void *arg) | ||
94 | { | ||
95 | struct manager *mgr = fi->userdata; | ||
96 | |||
97 | if (fi->state == ST_L1_DEACT_PENDING) | ||
98 | mISDN_FsmDelTimer(&mgr->datimer, 1); | ||
99 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | da_deactivate_ind(struct FsmInst *fi, int event, void *arg) | ||
104 | { | ||
105 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | da_deactivate(struct FsmInst *fi, int event, void *arg) | ||
110 | { | ||
111 | struct manager *mgr = fi->userdata; | ||
112 | struct layer2 *l2; | ||
113 | u_long flags; | ||
114 | |||
115 | read_lock_irqsave(&mgr->lock, flags); | ||
116 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
117 | if (l2->l2m.state > ST_L2_4) { | ||
118 | /* have still activ TEI */ | ||
119 | read_unlock_irqrestore(&mgr->lock, flags); | ||
120 | return; | ||
121 | } | ||
122 | } | ||
123 | read_unlock_irqrestore(&mgr->lock, flags); | ||
124 | /* All TEI are inactiv */ | ||
125 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); | ||
126 | mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | da_ui(struct FsmInst *fi, int event, void *arg) | ||
131 | { | ||
132 | struct manager *mgr = fi->userdata; | ||
133 | |||
134 | /* restart da timer */ | ||
135 | mISDN_FsmDelTimer(&mgr->datimer, 2); | ||
136 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); | ||
137 | |||
138 | } | ||
139 | |||
140 | static void | ||
141 | da_timer(struct FsmInst *fi, int event, void *arg) | ||
142 | { | ||
143 | struct manager *mgr = fi->userdata; | ||
144 | struct layer2 *l2; | ||
145 | u_long flags; | ||
146 | |||
147 | /* check again */ | ||
148 | read_lock_irqsave(&mgr->lock, flags); | ||
149 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
150 | if (l2->l2m.state > ST_L2_4) { | ||
151 | /* have still activ TEI */ | ||
152 | read_unlock_irqrestore(&mgr->lock, flags); | ||
153 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
154 | return; | ||
155 | } | ||
156 | } | ||
157 | read_unlock_irqrestore(&mgr->lock, flags); | ||
158 | /* All TEI are inactiv */ | ||
159 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
160 | _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, | ||
161 | GFP_ATOMIC); | ||
162 | } | ||
163 | |||
164 | static struct FsmNode DeactFnList[] = | ||
165 | { | ||
166 | {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, | ||
167 | {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, | ||
168 | {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, | ||
169 | {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, | ||
170 | {ST_L1_DEACT_PENDING, EV_UI, da_ui}, | ||
171 | {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, | ||
172 | }; | ||
173 | |||
174 | enum { | ||
175 | ST_TEI_NOP, | ||
176 | ST_TEI_IDREQ, | ||
177 | ST_TEI_IDVERIFY, | ||
178 | }; | ||
179 | |||
180 | #define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) | ||
181 | |||
182 | static char *strTeiState[] = | ||
183 | { | ||
184 | "ST_TEI_NOP", | ||
185 | "ST_TEI_IDREQ", | ||
186 | "ST_TEI_IDVERIFY", | ||
187 | }; | ||
188 | |||
189 | enum { | ||
190 | EV_IDREQ, | ||
191 | EV_ASSIGN, | ||
192 | EV_ASSIGN_REQ, | ||
193 | EV_DENIED, | ||
194 | EV_CHKREQ, | ||
195 | EV_CHKRESP, | ||
196 | EV_REMOVE, | ||
197 | EV_VERIFY, | ||
198 | EV_TIMER, | ||
199 | }; | ||
200 | |||
201 | #define TEI_EVENT_COUNT (EV_TIMER+1) | ||
202 | |||
203 | static char *strTeiEvent[] = | ||
204 | { | ||
205 | "EV_IDREQ", | ||
206 | "EV_ASSIGN", | ||
207 | "EV_ASSIGN_REQ", | ||
208 | "EV_DENIED", | ||
209 | "EV_CHKREQ", | ||
210 | "EV_CHKRESP", | ||
211 | "EV_REMOVE", | ||
212 | "EV_VERIFY", | ||
213 | "EV_TIMER", | ||
214 | }; | ||
215 | |||
216 | static void | ||
217 | tei_debug(struct FsmInst *fi, char *fmt, ...) | ||
218 | { | ||
219 | struct teimgr *tm = fi->userdata; | ||
220 | va_list va; | ||
221 | |||
222 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
223 | return; | ||
224 | va_start(va, fmt); | ||
225 | printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); | ||
226 | vprintk(fmt, va); | ||
227 | printk("\n"); | ||
228 | va_end(va); | ||
229 | } | ||
230 | |||
231 | |||
232 | |||
233 | static int | ||
234 | get_free_id(struct manager *mgr) | ||
235 | { | ||
236 | u64 ids = 0; | ||
237 | int i; | ||
238 | struct layer2 *l2; | ||
239 | |||
240 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
241 | if (l2->ch.nr > 63) { | ||
242 | printk(KERN_WARNING | ||
243 | "%s: more as 63 layer2 for one device\n", | ||
244 | __func__); | ||
245 | return -EBUSY; | ||
246 | } | ||
247 | test_and_set_bit(l2->ch.nr, (u_long *)&ids); | ||
248 | } | ||
249 | for (i = 1; i < 64; i++) | ||
250 | if (!test_bit(i, (u_long *)&ids)) | ||
251 | return i; | ||
252 | printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", | ||
253 | __func__); | ||
254 | return -EBUSY; | ||
255 | } | ||
256 | |||
257 | static int | ||
258 | get_free_tei(struct manager *mgr) | ||
259 | { | ||
260 | u64 ids = 0; | ||
261 | int i; | ||
262 | struct layer2 *l2; | ||
263 | |||
264 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
265 | if (l2->ch.nr == 0) | ||
266 | continue; | ||
267 | if ((l2->ch.addr & 0xff) != 0) | ||
268 | continue; | ||
269 | i = l2->ch.addr >> 8; | ||
270 | if (i < 64) | ||
271 | continue; | ||
272 | i -= 64; | ||
273 | |||
274 | test_and_set_bit(i, (u_long *)&ids); | ||
275 | } | ||
276 | for (i = 0; i < 64; i++) | ||
277 | if (!test_bit(i, (u_long *)&ids)) | ||
278 | return i + 64; | ||
279 | printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", | ||
280 | __func__); | ||
281 | return -1; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | teiup_create(struct manager *mgr, u_int prim, int len, void *arg) | ||
286 | { | ||
287 | struct sk_buff *skb; | ||
288 | struct mISDNhead *hh; | ||
289 | int err; | ||
290 | |||
291 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
292 | if (!skb) | ||
293 | return; | ||
294 | hh = mISDN_HEAD_P(skb); | ||
295 | hh->prim = prim; | ||
296 | hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; | ||
297 | if (len) | ||
298 | memcpy(skb_put(skb, len), arg, len); | ||
299 | err = mgr->up->send(mgr->up, skb); | ||
300 | if (err) { | ||
301 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
302 | dev_kfree_skb(skb); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static u_int | ||
307 | new_id(struct manager *mgr) | ||
308 | { | ||
309 | u_int id; | ||
310 | |||
311 | id = mgr->nextid++; | ||
312 | if (id == 0x7fff) | ||
313 | mgr->nextid = 1; | ||
314 | id <<= 16; | ||
315 | id |= GROUP_TEI << 8; | ||
316 | id |= TEI_SAPI; | ||
317 | return id; | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | do_send(struct manager *mgr) | ||
322 | { | ||
323 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
324 | return; | ||
325 | |||
326 | if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
327 | struct sk_buff *skb = skb_dequeue(&mgr->sendq); | ||
328 | |||
329 | if (!skb) { | ||
330 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
331 | return; | ||
332 | } | ||
333 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
334 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
335 | if (mgr->ch.recv(mgr->ch.peer, skb)) { | ||
336 | dev_kfree_skb(skb); | ||
337 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
338 | mgr->lastid = MISDN_ID_NONE; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static void | ||
344 | do_ack(struct manager *mgr, u_int id) | ||
345 | { | ||
346 | if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
347 | if (id == mgr->lastid) { | ||
348 | if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
349 | struct sk_buff *skb; | ||
350 | |||
351 | skb = skb_dequeue(&mgr->sendq); | ||
352 | if (skb) { | ||
353 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
354 | if (!mgr->ch.recv(mgr->ch.peer, skb)) | ||
355 | return; | ||
356 | dev_kfree_skb(skb); | ||
357 | } | ||
358 | } | ||
359 | mgr->lastid = MISDN_ID_NONE; | ||
360 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | mgr_send_down(struct manager *mgr, struct sk_buff *skb) | ||
367 | { | ||
368 | skb_queue_tail(&mgr->sendq, skb); | ||
369 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
370 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
371 | NULL, GFP_KERNEL); | ||
372 | } else { | ||
373 | do_send(mgr); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | static int | ||
378 | dl_unit_data(struct manager *mgr, struct sk_buff *skb) | ||
379 | { | ||
380 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ | ||
381 | return -EINVAL; | ||
382 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
383 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
384 | NULL, GFP_KERNEL); | ||
385 | skb_push(skb, 3); | ||
386 | skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ | ||
387 | skb->data[1] = 0xff; /* TEI 127 */ | ||
388 | skb->data[2] = UI; /* UI frame */ | ||
389 | mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; | ||
390 | mISDN_HEAD_ID(skb) = new_id(mgr); | ||
391 | skb_queue_tail(&mgr->sendq, skb); | ||
392 | do_send(mgr); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | unsigned int | ||
397 | random_ri(void) | ||
398 | { | ||
399 | u16 x; | ||
400 | |||
401 | get_random_bytes(&x, sizeof(x)); | ||
402 | return x; | ||
403 | } | ||
404 | |||
405 | static struct layer2 * | ||
406 | findtei(struct manager *mgr, int tei) | ||
407 | { | ||
408 | struct layer2 *l2; | ||
409 | u_long flags; | ||
410 | |||
411 | read_lock_irqsave(&mgr->lock, flags); | ||
412 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
413 | if ((l2->sapi == 0) && (l2->tei > 0) && | ||
414 | (l2->tei != GROUP_TEI) && (l2->tei == tei)) | ||
415 | goto done; | ||
416 | } | ||
417 | l2 = NULL; | ||
418 | done: | ||
419 | read_unlock_irqrestore(&mgr->lock, flags); | ||
420 | return l2; | ||
421 | } | ||
422 | |||
423 | static void | ||
424 | put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) | ||
425 | { | ||
426 | struct sk_buff *skb; | ||
427 | u_char bp[8]; | ||
428 | |||
429 | bp[0] = (TEI_SAPI << 2); | ||
430 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
431 | bp[0] |= 2; /* CR:=1 for net command */ | ||
432 | bp[1] = (GROUP_TEI << 1) | 0x1; | ||
433 | bp[2] = UI; | ||
434 | bp[3] = TEI_ENTITY_ID; | ||
435 | bp[4] = ri >> 8; | ||
436 | bp[5] = ri & 0xff; | ||
437 | bp[6] = m_id; | ||
438 | bp[7] = (tei << 1) | 1; | ||
439 | skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), | ||
440 | 8, bp, GFP_ATOMIC); | ||
441 | if (!skb) { | ||
442 | printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); | ||
443 | return; | ||
444 | } | ||
445 | mgr_send_down(mgr, skb); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | tei_id_request(struct FsmInst *fi, int event, void *arg) | ||
450 | { | ||
451 | struct teimgr *tm = fi->userdata; | ||
452 | |||
453 | if (tm->l2->tei != GROUP_TEI) { | ||
454 | tm->tei_m.printdebug(&tm->tei_m, | ||
455 | "assign request for allready assigned tei %d", | ||
456 | tm->l2->tei); | ||
457 | return; | ||
458 | } | ||
459 | tm->ri = random_ri(); | ||
460 | if (*debug & DEBUG_L2_TEI) | ||
461 | tm->tei_m.printdebug(&tm->tei_m, | ||
462 | "assign request ri %d", tm->ri); | ||
463 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
464 | mISDN_FsmChangeState(fi, ST_TEI_IDREQ); | ||
465 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); | ||
466 | tm->nval = 3; | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | tei_id_assign(struct FsmInst *fi, int event, void *arg) | ||
471 | { | ||
472 | struct teimgr *tm = fi->userdata; | ||
473 | struct layer2 *l2; | ||
474 | u_char *dp = arg; | ||
475 | int ri, tei; | ||
476 | |||
477 | ri = ((unsigned int) *dp++ << 8); | ||
478 | ri += *dp++; | ||
479 | dp++; | ||
480 | tei = *dp >> 1; | ||
481 | if (*debug & DEBUG_L2_TEI) | ||
482 | tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", | ||
483 | ri, tei); | ||
484 | l2 = findtei(tm->mgr, tei); | ||
485 | if (l2) { /* same tei is in use */ | ||
486 | if (ri != l2->tm->ri) { | ||
487 | tm->tei_m.printdebug(fi, | ||
488 | "possible duplicate assignment tei %d", tei); | ||
489 | tei_l2(l2, MDL_ERROR_RSP, 0); | ||
490 | } | ||
491 | } else if (ri == tm->ri) { | ||
492 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
493 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
494 | tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void | ||
499 | tei_id_test_dup(struct FsmInst *fi, int event, void *arg) | ||
500 | { | ||
501 | struct teimgr *tm = fi->userdata; | ||
502 | struct layer2 *l2; | ||
503 | u_char *dp = arg; | ||
504 | int tei, ri; | ||
505 | |||
506 | ri = ((unsigned int) *dp++ << 8); | ||
507 | ri += *dp++; | ||
508 | dp++; | ||
509 | tei = *dp >> 1; | ||
510 | if (*debug & DEBUG_L2_TEI) | ||
511 | tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", | ||
512 | ri, tei); | ||
513 | l2 = findtei(tm->mgr, tei); | ||
514 | if (l2) { /* same tei is in use */ | ||
515 | if (ri != l2->tm->ri) { /* and it wasn't our request */ | ||
516 | tm->tei_m.printdebug(fi, | ||
517 | "possible duplicate assignment tei %d", tei); | ||
518 | mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | static void | ||
524 | tei_id_denied(struct FsmInst *fi, int event, void *arg) | ||
525 | { | ||
526 | struct teimgr *tm = fi->userdata; | ||
527 | u_char *dp = arg; | ||
528 | int ri, tei; | ||
529 | |||
530 | ri = ((unsigned int) *dp++ << 8); | ||
531 | ri += *dp++; | ||
532 | dp++; | ||
533 | tei = *dp >> 1; | ||
534 | if (*debug & DEBUG_L2_TEI) | ||
535 | tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", | ||
536 | ri, tei); | ||
537 | } | ||
538 | |||
539 | static void | ||
540 | tei_id_chk_req(struct FsmInst *fi, int event, void *arg) | ||
541 | { | ||
542 | struct teimgr *tm = fi->userdata; | ||
543 | u_char *dp = arg; | ||
544 | int tei; | ||
545 | |||
546 | tei = *(dp+3) >> 1; | ||
547 | if (*debug & DEBUG_L2_TEI) | ||
548 | tm->tei_m.printdebug(fi, "identity check req tei %d", tei); | ||
549 | if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || | ||
550 | (tei == tm->l2->tei))) { | ||
551 | mISDN_FsmDelTimer(&tm->timer, 4); | ||
552 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
553 | put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void | ||
558 | tei_id_remove(struct FsmInst *fi, int event, void *arg) | ||
559 | { | ||
560 | struct teimgr *tm = fi->userdata; | ||
561 | u_char *dp = arg; | ||
562 | int tei; | ||
563 | |||
564 | tei = *(dp+3) >> 1; | ||
565 | if (*debug & DEBUG_L2_TEI) | ||
566 | tm->tei_m.printdebug(fi, "identity remove tei %d", tei); | ||
567 | if ((tm->l2->tei != GROUP_TEI) && | ||
568 | ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { | ||
569 | mISDN_FsmDelTimer(&tm->timer, 5); | ||
570 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
571 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | static void | ||
576 | tei_id_verify(struct FsmInst *fi, int event, void *arg) | ||
577 | { | ||
578 | struct teimgr *tm = fi->userdata; | ||
579 | |||
580 | if (*debug & DEBUG_L2_TEI) | ||
581 | tm->tei_m.printdebug(fi, "id verify request for tei %d", | ||
582 | tm->l2->tei); | ||
583 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
584 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
585 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
586 | tm->nval = 2; | ||
587 | } | ||
588 | |||
589 | static void | ||
590 | tei_id_req_tout(struct FsmInst *fi, int event, void *arg) | ||
591 | { | ||
592 | struct teimgr *tm = fi->userdata; | ||
593 | |||
594 | if (--tm->nval) { | ||
595 | tm->ri = random_ri(); | ||
596 | if (*debug & DEBUG_L2_TEI) | ||
597 | tm->tei_m.printdebug(fi, "assign req(%d) ri %d", | ||
598 | 4 - tm->nval, tm->ri); | ||
599 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
600 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); | ||
601 | } else { | ||
602 | tm->tei_m.printdebug(fi, "assign req failed"); | ||
603 | tei_l2(tm->l2, MDL_ERROR_RSP, 0); | ||
604 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static void | ||
609 | tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) | ||
610 | { | ||
611 | struct teimgr *tm = fi->userdata; | ||
612 | |||
613 | if (--tm->nval) { | ||
614 | if (*debug & DEBUG_L2_TEI) | ||
615 | tm->tei_m.printdebug(fi, | ||
616 | "id verify req(%d) for tei %d", | ||
617 | 3 - tm->nval, tm->l2->tei); | ||
618 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
619 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
620 | } else { | ||
621 | tm->tei_m.printdebug(fi, "verify req for tei %d failed", | ||
622 | tm->l2->tei); | ||
623 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
624 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | static struct FsmNode TeiFnListUser[] = | ||
629 | { | ||
630 | {ST_TEI_NOP, EV_IDREQ, tei_id_request}, | ||
631 | {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, | ||
632 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, | ||
633 | {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, | ||
634 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, | ||
635 | {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, | ||
636 | {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, | ||
637 | {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, | ||
638 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, | ||
639 | {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, | ||
640 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | ||
641 | }; | ||
642 | |||
643 | static void | ||
644 | tei_l2remove(struct layer2 *l2) | ||
645 | { | ||
646 | put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); | ||
647 | tei_l2(l2, MDL_REMOVE_REQ, 0); | ||
648 | list_del(&l2->ch.list); | ||
649 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
650 | } | ||
651 | |||
652 | static void | ||
653 | tei_assign_req(struct FsmInst *fi, int event, void *arg) | ||
654 | { | ||
655 | struct teimgr *tm = fi->userdata; | ||
656 | u_char *dp = arg; | ||
657 | |||
658 | if (tm->l2->tei == GROUP_TEI) { | ||
659 | tm->tei_m.printdebug(&tm->tei_m, | ||
660 | "net tei assign request without tei"); | ||
661 | return; | ||
662 | } | ||
663 | tm->ri = ((unsigned int) *dp++ << 8); | ||
664 | tm->ri += *dp++; | ||
665 | if (*debug & DEBUG_L2_TEI) | ||
666 | tm->tei_m.printdebug(&tm->tei_m, | ||
667 | "net assign request ri %d teim %d", tm->ri, *dp); | ||
668 | put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); | ||
669 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
670 | } | ||
671 | |||
672 | static void | ||
673 | tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) | ||
674 | { | ||
675 | struct teimgr *tm = fi->userdata; | ||
676 | |||
677 | if (*debug & DEBUG_L2_TEI) | ||
678 | tm->tei_m.printdebug(fi, "id check request for tei %d", | ||
679 | tm->l2->tei); | ||
680 | tm->rcnt = 0; | ||
681 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
682 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
683 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
684 | tm->nval = 2; | ||
685 | } | ||
686 | |||
687 | static void | ||
688 | tei_id_chk_resp(struct FsmInst *fi, int event, void *arg) | ||
689 | { | ||
690 | struct teimgr *tm = fi->userdata; | ||
691 | u_char *dp = arg; | ||
692 | int tei; | ||
693 | |||
694 | tei = dp[3] >> 1; | ||
695 | if (*debug & DEBUG_L2_TEI) | ||
696 | tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); | ||
697 | if (tei == tm->l2->tei) | ||
698 | tm->rcnt++; | ||
699 | } | ||
700 | |||
701 | static void | ||
702 | tei_id_verify_net(struct FsmInst *fi, int event, void *arg) | ||
703 | { | ||
704 | struct teimgr *tm = fi->userdata; | ||
705 | u_char *dp = arg; | ||
706 | int tei; | ||
707 | |||
708 | tei = dp[3] >> 1; | ||
709 | if (*debug & DEBUG_L2_TEI) | ||
710 | tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", | ||
711 | tei, tm->l2->tei); | ||
712 | if (tei == tm->l2->tei) | ||
713 | tei_id_chk_req_net(fi, event, arg); | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) | ||
718 | { | ||
719 | struct teimgr *tm = fi->userdata; | ||
720 | |||
721 | if (tm->rcnt == 1) { | ||
722 | if (*debug & DEBUG_L2_TEI) | ||
723 | tm->tei_m.printdebug(fi, | ||
724 | "check req for tei %d sucessful\n", tm->l2->tei); | ||
725 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
726 | } else if (tm->rcnt > 1) { | ||
727 | /* duplicate assignment; remove */ | ||
728 | tei_l2remove(tm->l2); | ||
729 | } else if (--tm->nval) { | ||
730 | if (*debug & DEBUG_L2_TEI) | ||
731 | tm->tei_m.printdebug(fi, | ||
732 | "id check req(%d) for tei %d", | ||
733 | 3 - tm->nval, tm->l2->tei); | ||
734 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
735 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
736 | } else { | ||
737 | tm->tei_m.printdebug(fi, "check req for tei %d failed", | ||
738 | tm->l2->tei); | ||
739 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
740 | tei_l2remove(tm->l2); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static struct FsmNode TeiFnListNet[] = | ||
745 | { | ||
746 | {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, | ||
747 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, | ||
748 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, | ||
749 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, | ||
750 | {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, | ||
751 | }; | ||
752 | |||
753 | static void | ||
754 | tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) | ||
755 | { | ||
756 | if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) | ||
757 | return; | ||
758 | if (*debug & DEBUG_L2_TEI) | ||
759 | tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); | ||
760 | if (mt == ID_ASSIGNED) | ||
761 | mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); | ||
762 | else if (mt == ID_DENIED) | ||
763 | mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); | ||
764 | else if (mt == ID_CHK_REQ) | ||
765 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); | ||
766 | else if (mt == ID_REMOVE) | ||
767 | mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); | ||
768 | else if (mt == ID_VERIFY) | ||
769 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); | ||
770 | else if (mt == ID_CHK_RES) | ||
771 | mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); | ||
772 | } | ||
773 | |||
774 | static struct layer2 * | ||
775 | create_new_tei(struct manager *mgr, int tei) | ||
776 | { | ||
777 | u_long opt = 0; | ||
778 | u_long flags; | ||
779 | int id; | ||
780 | struct layer2 *l2; | ||
781 | |||
782 | if (!mgr->up) | ||
783 | return NULL; | ||
784 | if (tei < 64) | ||
785 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
786 | if (mgr->ch.st->dev->Dprotocols | ||
787 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
788 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
789 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); | ||
790 | if (!l2) { | ||
791 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); | ||
792 | return NULL; | ||
793 | } | ||
794 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
795 | if (!l2->tm) { | ||
796 | kfree(l2); | ||
797 | printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); | ||
798 | return NULL; | ||
799 | } | ||
800 | l2->tm->mgr = mgr; | ||
801 | l2->tm->l2 = l2; | ||
802 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
803 | l2->tm->tei_m.userdata = l2->tm; | ||
804 | l2->tm->tei_m.printdebug = tei_debug; | ||
805 | l2->tm->tei_m.fsm = &teifsmn; | ||
806 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
807 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
808 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
809 | write_lock_irqsave(&mgr->lock, flags); | ||
810 | id = get_free_id(mgr); | ||
811 | list_add_tail(&l2->list, &mgr->layer2); | ||
812 | write_unlock_irqrestore(&mgr->lock, flags); | ||
813 | if (id < 0) { | ||
814 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
815 | printk(KERN_WARNING "%s:no free id\n", __func__); | ||
816 | return NULL; | ||
817 | } else { | ||
818 | l2->ch.nr = id; | ||
819 | __add_layer2(&l2->ch, mgr->ch.st); | ||
820 | l2->ch.recv = mgr->ch.recv; | ||
821 | l2->ch.peer = mgr->ch.peer; | ||
822 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
823 | } | ||
824 | return l2; | ||
825 | } | ||
826 | |||
827 | static void | ||
828 | new_tei_req(struct manager *mgr, u_char *dp) | ||
829 | { | ||
830 | int tei, ri; | ||
831 | struct layer2 *l2; | ||
832 | |||
833 | ri = dp[0] << 8; | ||
834 | ri += dp[1]; | ||
835 | if (!mgr->up) | ||
836 | goto denied; | ||
837 | tei = get_free_tei(mgr); | ||
838 | if (tei < 0) { | ||
839 | printk(KERN_WARNING "%s:No free tei\n", __func__); | ||
840 | goto denied; | ||
841 | } | ||
842 | l2 = create_new_tei(mgr, tei); | ||
843 | if (!l2) | ||
844 | goto denied; | ||
845 | else | ||
846 | mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); | ||
847 | return; | ||
848 | denied: | ||
849 | put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); | ||
850 | } | ||
851 | |||
852 | static int | ||
853 | ph_data_ind(struct manager *mgr, struct sk_buff *skb) | ||
854 | { | ||
855 | int ret = -EINVAL; | ||
856 | struct layer2 *l2; | ||
857 | u_long flags; | ||
858 | u_char mt; | ||
859 | |||
860 | if (skb->len < 8) { | ||
861 | if (*debug & DEBUG_L2_TEI) | ||
862 | printk(KERN_DEBUG "%s: short mgr frame %d/8\n", | ||
863 | __func__, skb->len); | ||
864 | goto done; | ||
865 | } | ||
866 | if (*debug & DEBUG_L2_TEI) | ||
867 | |||
868 | if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ | ||
869 | goto done; | ||
870 | if (skb->data[0] & 1) /* EA0 formal error */ | ||
871 | goto done; | ||
872 | if (!(skb->data[1] & 1)) /* EA1 formal error */ | ||
873 | goto done; | ||
874 | if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ | ||
875 | goto done; | ||
876 | if ((skb->data[2] & 0xef) != UI) /* not UI */ | ||
877 | goto done; | ||
878 | if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ | ||
879 | goto done; | ||
880 | mt = skb->data[6]; | ||
881 | switch (mt) { | ||
882 | case ID_REQUEST: | ||
883 | case ID_CHK_RES: | ||
884 | case ID_VERIFY: | ||
885 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
886 | goto done; | ||
887 | break; | ||
888 | case ID_ASSIGNED: | ||
889 | case ID_DENIED: | ||
890 | case ID_CHK_REQ: | ||
891 | case ID_REMOVE: | ||
892 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
893 | goto done; | ||
894 | break; | ||
895 | default: | ||
896 | goto done; | ||
897 | } | ||
898 | ret = 0; | ||
899 | if (mt == ID_REQUEST) { | ||
900 | new_tei_req(mgr, &skb->data[4]); | ||
901 | goto done; | ||
902 | } | ||
903 | read_lock_irqsave(&mgr->lock, flags); | ||
904 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
905 | tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); | ||
906 | } | ||
907 | read_unlock_irqrestore(&mgr->lock, flags); | ||
908 | done: | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | int | ||
913 | l2_tei(struct layer2 *l2, u_int cmd, u_long arg) | ||
914 | { | ||
915 | struct teimgr *tm = l2->tm; | ||
916 | |||
917 | if (test_bit(FLG_FIXED_TEI, &l2->flag)) | ||
918 | return 0; | ||
919 | if (*debug & DEBUG_L2_TEI) | ||
920 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
921 | switch (cmd) { | ||
922 | case MDL_ASSIGN_IND: | ||
923 | mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); | ||
924 | break; | ||
925 | case MDL_ERROR_IND: | ||
926 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
927 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); | ||
928 | if (test_bit(MGR_OPT_USER, &tm->mgr->options)) | ||
929 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); | ||
930 | break; | ||
931 | case MDL_STATUS_UP_IND: | ||
932 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
933 | mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); | ||
934 | break; | ||
935 | case MDL_STATUS_DOWN_IND: | ||
936 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
937 | mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); | ||
938 | break; | ||
939 | case MDL_STATUS_UI_IND: | ||
940 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
941 | mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); | ||
942 | break; | ||
943 | } | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | void | ||
948 | release_tei(struct layer2 *l2) | ||
949 | { | ||
950 | struct teimgr *tm = l2->tm; | ||
951 | u_long flags; | ||
952 | |||
953 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
954 | write_lock_irqsave(&tm->mgr->lock, flags); | ||
955 | list_del(&l2->list); | ||
956 | write_unlock_irqrestore(&tm->mgr->lock, flags); | ||
957 | l2->tm = NULL; | ||
958 | kfree(tm); | ||
959 | } | ||
960 | |||
961 | static int | ||
962 | create_teimgr(struct manager *mgr, struct channel_req *crq) | ||
963 | { | ||
964 | struct layer2 *l2; | ||
965 | u_long opt = 0; | ||
966 | u_long flags; | ||
967 | int id; | ||
968 | |||
969 | if (*debug & DEBUG_L2_TEI) | ||
970 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
971 | __func__, mgr->ch.st->dev->name, crq->protocol, | ||
972 | crq->adr.dev, crq->adr.channel, crq->adr.sapi, | ||
973 | crq->adr.tei); | ||
974 | if (crq->adr.sapi != 0) /* not supported yet */ | ||
975 | return -EINVAL; | ||
976 | if (crq->adr.tei > GROUP_TEI) | ||
977 | return -EINVAL; | ||
978 | if (crq->adr.tei < 64) | ||
979 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
980 | if (crq->adr.tei == 0) | ||
981 | test_and_set_bit(OPTION_L2_PTP, &opt); | ||
982 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
983 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
984 | return -EPROTONOSUPPORT; | ||
985 | if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) | ||
986 | return -EINVAL; | ||
987 | if (mgr->up) { | ||
988 | printk(KERN_WARNING | ||
989 | "%s: only one network manager is allowed\n", | ||
990 | __func__); | ||
991 | return -EBUSY; | ||
992 | } | ||
993 | } else if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
994 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
995 | return -EPROTONOSUPPORT; | ||
996 | if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) | ||
997 | return -EINVAL; /* dyn tei */ | ||
998 | } else { | ||
999 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
1000 | test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1001 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
1002 | test_and_set_bit(MGR_OPT_USER, &mgr->options); | ||
1003 | } | ||
1004 | if (mgr->ch.st->dev->Dprotocols | ||
1005 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
1006 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
1007 | if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { | ||
1008 | mgr->up = crq->ch; | ||
1009 | id = DL_INFO_L2_CONNECT; | ||
1010 | teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); | ||
1011 | crq->ch = NULL; | ||
1012 | if (!list_empty(&mgr->layer2)) { | ||
1013 | read_lock_irqsave(&mgr->lock, flags); | ||
1014 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1015 | l2->up = mgr->up; | ||
1016 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
1017 | } | ||
1018 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1019 | } | ||
1020 | return 0; | ||
1021 | } | ||
1022 | l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, | ||
1023 | (u_long)crq->adr.tei); | ||
1024 | if (!l2) | ||
1025 | return -ENOMEM; | ||
1026 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
1027 | if (!l2->tm) { | ||
1028 | kfree(l2); | ||
1029 | printk(KERN_ERR "kmalloc teimgr failed\n"); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | l2->tm->mgr = mgr; | ||
1033 | l2->tm->l2 = l2; | ||
1034 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
1035 | l2->tm->tei_m.userdata = l2->tm; | ||
1036 | l2->tm->tei_m.printdebug = tei_debug; | ||
1037 | if (crq->protocol == ISDN_P_LAPD_TE) { | ||
1038 | l2->tm->tei_m.fsm = &teifsmu; | ||
1039 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1040 | l2->tm->tval = 1000; /* T201 1 sec */ | ||
1041 | } else { | ||
1042 | l2->tm->tei_m.fsm = &teifsmn; | ||
1043 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
1044 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
1045 | } | ||
1046 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
1047 | write_lock_irqsave(&mgr->lock, flags); | ||
1048 | id = get_free_id(mgr); | ||
1049 | list_add_tail(&l2->list, &mgr->layer2); | ||
1050 | write_unlock_irqrestore(&mgr->lock, flags); | ||
1051 | if (id < 0) { | ||
1052 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1053 | } else { | ||
1054 | l2->ch.nr = id; | ||
1055 | l2->up->nr = id; | ||
1056 | crq->ch = &l2->ch; | ||
1057 | id = 0; | ||
1058 | } | ||
1059 | return id; | ||
1060 | } | ||
1061 | |||
1062 | static int | ||
1063 | mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1064 | { | ||
1065 | struct manager *mgr; | ||
1066 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1067 | int ret = -EINVAL; | ||
1068 | |||
1069 | mgr = container_of(ch, struct manager, ch); | ||
1070 | if (*debug & DEBUG_L2_RECV) | ||
1071 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1072 | __func__, hh->prim, hh->id); | ||
1073 | switch (hh->prim) { | ||
1074 | case PH_DATA_IND: | ||
1075 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
1076 | ret = ph_data_ind(mgr, skb); | ||
1077 | break; | ||
1078 | case PH_DATA_CNF: | ||
1079 | do_ack(mgr, hh->id); | ||
1080 | ret = 0; | ||
1081 | break; | ||
1082 | case PH_ACTIVATE_IND: | ||
1083 | test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1084 | mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); | ||
1085 | do_send(mgr); | ||
1086 | ret = 0; | ||
1087 | break; | ||
1088 | case PH_DEACTIVATE_IND: | ||
1089 | test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); | ||
1090 | mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); | ||
1091 | ret = 0; | ||
1092 | break; | ||
1093 | case DL_UNITDATA_REQ: | ||
1094 | return dl_unit_data(mgr, skb); | ||
1095 | } | ||
1096 | if (!ret) | ||
1097 | dev_kfree_skb(skb); | ||
1098 | return ret; | ||
1099 | } | ||
1100 | |||
1101 | static int | ||
1102 | free_teimanager(struct manager *mgr) | ||
1103 | { | ||
1104 | struct layer2 *l2, *nl2; | ||
1105 | |||
1106 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
1107 | /* not locked lock is taken in release tei */ | ||
1108 | mgr->up = NULL; | ||
1109 | if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { | ||
1110 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1111 | put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); | ||
1112 | mutex_lock(&mgr->ch.st->lmutex); | ||
1113 | list_del(&l2->ch.list); | ||
1114 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1115 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1116 | } | ||
1117 | test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); | ||
1118 | } else { | ||
1119 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1120 | l2->up = NULL; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
1125 | if (list_empty(&mgr->layer2)) | ||
1126 | test_and_clear_bit(MGR_OPT_USER, &mgr->options); | ||
1127 | } | ||
1128 | mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int | ||
1133 | ctrl_teimanager(struct manager *mgr, void *arg) | ||
1134 | { | ||
1135 | /* currently we only have one option */ | ||
1136 | int clean = *((int *)arg); | ||
1137 | |||
1138 | if (clean) | ||
1139 | test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1140 | else | ||
1141 | test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* This function does create a L2 for fixed TEI in NT Mode */ | ||
1146 | static int | ||
1147 | check_data(struct manager *mgr, struct sk_buff *skb) | ||
1148 | { | ||
1149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1150 | int ret, tei; | ||
1151 | struct layer2 *l2; | ||
1152 | |||
1153 | if (*debug & DEBUG_L2_CTRL) | ||
1154 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
1155 | __func__, hh->prim, hh->id); | ||
1156 | if (test_bit(MGR_OPT_USER, &mgr->options)) | ||
1157 | return -ENOTCONN; | ||
1158 | if (hh->prim != PH_DATA_IND) | ||
1159 | return -ENOTCONN; | ||
1160 | if (skb->len != 3) | ||
1161 | return -ENOTCONN; | ||
1162 | if (skb->data[0] != 0) | ||
1163 | /* only SAPI 0 command */ | ||
1164 | return -ENOTCONN; | ||
1165 | if (!(skb->data[1] & 1)) /* invalid EA1 */ | ||
1166 | return -EINVAL; | ||
1167 | tei = skb->data[1] >> 0; | ||
1168 | if (tei > 63) /* not a fixed tei */ | ||
1169 | return -ENOTCONN; | ||
1170 | if ((skb->data[2] & ~0x10) != SABME) | ||
1171 | return -ENOTCONN; | ||
1172 | /* We got a SABME for a fixed TEI */ | ||
1173 | l2 = create_new_tei(mgr, tei); | ||
1174 | if (!l2) | ||
1175 | return -ENOMEM; | ||
1176 | ret = l2->ch.send(&l2->ch, skb); | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1180 | void | ||
1181 | delete_teimanager(struct mISDNchannel *ch) | ||
1182 | { | ||
1183 | struct manager *mgr; | ||
1184 | struct layer2 *l2, *nl2; | ||
1185 | |||
1186 | mgr = container_of(ch, struct manager, ch); | ||
1187 | /* not locked lock is taken in release tei */ | ||
1188 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
1189 | mutex_lock(&mgr->ch.st->lmutex); | ||
1190 | list_del(&l2->ch.list); | ||
1191 | mutex_unlock(&mgr->ch.st->lmutex); | ||
1192 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1193 | } | ||
1194 | list_del(&mgr->ch.list); | ||
1195 | list_del(&mgr->bcast.list); | ||
1196 | skb_queue_purge(&mgr->sendq); | ||
1197 | kfree(mgr); | ||
1198 | } | ||
1199 | |||
1200 | static int | ||
1201 | mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1202 | { | ||
1203 | struct manager *mgr; | ||
1204 | int ret = -EINVAL; | ||
1205 | |||
1206 | mgr = container_of(ch, struct manager, ch); | ||
1207 | if (*debug & DEBUG_L2_CTRL) | ||
1208 | printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); | ||
1209 | switch (cmd) { | ||
1210 | case OPEN_CHANNEL: | ||
1211 | ret = create_teimgr(mgr, arg); | ||
1212 | break; | ||
1213 | case CLOSE_CHANNEL: | ||
1214 | ret = free_teimanager(mgr); | ||
1215 | break; | ||
1216 | case CONTROL_CHANNEL: | ||
1217 | ret = ctrl_teimanager(mgr, arg); | ||
1218 | break; | ||
1219 | case CHECK_DATA: | ||
1220 | ret = check_data(mgr, arg); | ||
1221 | break; | ||
1222 | } | ||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | static int | ||
1227 | mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) | ||
1228 | { | ||
1229 | struct manager *mgr = container_of(ch, struct manager, bcast); | ||
1230 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
1231 | struct sk_buff *cskb = NULL; | ||
1232 | struct layer2 *l2; | ||
1233 | u_long flags; | ||
1234 | int ret; | ||
1235 | |||
1236 | read_lock_irqsave(&mgr->lock, flags); | ||
1237 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
1238 | if ((hh->id & MISDN_ID_SAPI_MASK) == | ||
1239 | (l2->ch.addr & MISDN_ID_SAPI_MASK)) { | ||
1240 | if (list_is_last(&l2->list, &mgr->layer2)) { | ||
1241 | cskb = skb; | ||
1242 | skb = NULL; | ||
1243 | } else { | ||
1244 | if (!cskb) | ||
1245 | cskb = skb_copy(skb, GFP_KERNEL); | ||
1246 | } | ||
1247 | if (cskb) { | ||
1248 | ret = l2->ch.send(&l2->ch, cskb); | ||
1249 | if (ret) { | ||
1250 | if (*debug & DEBUG_SEND_ERR) | ||
1251 | printk(KERN_DEBUG | ||
1252 | "%s ch%d prim(%x) addr(%x)" | ||
1253 | " err %d\n", | ||
1254 | __func__, l2->ch.nr, | ||
1255 | hh->prim, l2->ch.addr, ret); | ||
1256 | } else | ||
1257 | cskb = NULL; | ||
1258 | } else { | ||
1259 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
1260 | __func__, ch->nr, ch->addr); | ||
1261 | goto out; | ||
1262 | } | ||
1263 | } | ||
1264 | } | ||
1265 | out: | ||
1266 | read_unlock_irqrestore(&mgr->lock, flags); | ||
1267 | if (cskb) | ||
1268 | dev_kfree_skb(cskb); | ||
1269 | if (skb) | ||
1270 | dev_kfree_skb(skb); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static int | ||
1275 | mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
1276 | { | ||
1277 | |||
1278 | return -EINVAL; | ||
1279 | } | ||
1280 | |||
1281 | int | ||
1282 | create_teimanager(struct mISDNdevice *dev) | ||
1283 | { | ||
1284 | struct manager *mgr; | ||
1285 | |||
1286 | mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); | ||
1287 | if (!mgr) | ||
1288 | return -ENOMEM; | ||
1289 | INIT_LIST_HEAD(&mgr->layer2); | ||
1290 | mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); | ||
1291 | skb_queue_head_init(&mgr->sendq); | ||
1292 | mgr->nextid = 1; | ||
1293 | mgr->lastid = MISDN_ID_NONE; | ||
1294 | mgr->ch.send = mgr_send; | ||
1295 | mgr->ch.ctrl = mgr_ctrl; | ||
1296 | mgr->ch.st = dev->D.st; | ||
1297 | set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); | ||
1298 | add_layer2(&mgr->ch, dev->D.st); | ||
1299 | mgr->bcast.send = mgr_bcast; | ||
1300 | mgr->bcast.ctrl = mgr_bcast_ctrl; | ||
1301 | mgr->bcast.st = dev->D.st; | ||
1302 | set_channel_address(&mgr->bcast, 0, GROUP_TEI); | ||
1303 | add_layer2(&mgr->bcast, dev->D.st); | ||
1304 | mgr->deact.debug = *debug & DEBUG_MANAGER; | ||
1305 | mgr->deact.userdata = mgr; | ||
1306 | mgr->deact.printdebug = da_debug; | ||
1307 | mgr->deact.fsm = &deactfsm; | ||
1308 | mgr->deact.state = ST_L1_DEACT; | ||
1309 | mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); | ||
1310 | dev->teimgr = &mgr->ch; | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | int TEIInit(u_int *deb) | ||
1315 | { | ||
1316 | debug = deb; | ||
1317 | teifsmu.state_count = TEI_STATE_COUNT; | ||
1318 | teifsmu.event_count = TEI_EVENT_COUNT; | ||
1319 | teifsmu.strEvent = strTeiEvent; | ||
1320 | teifsmu.strState = strTeiState; | ||
1321 | mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); | ||
1322 | teifsmn.state_count = TEI_STATE_COUNT; | ||
1323 | teifsmn.event_count = TEI_EVENT_COUNT; | ||
1324 | teifsmn.strEvent = strTeiEvent; | ||
1325 | teifsmn.strState = strTeiState; | ||
1326 | mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); | ||
1327 | deactfsm.state_count = DEACT_STATE_COUNT; | ||
1328 | deactfsm.event_count = DEACT_EVENT_COUNT; | ||
1329 | deactfsm.strEvent = strDeactEvent; | ||
1330 | deactfsm.strState = strDeactState; | ||
1331 | mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); | ||
1332 | return 0; | ||
1333 | } | ||
1334 | |||
1335 | void TEIFree(void) | ||
1336 | { | ||
1337 | mISDN_FsmFree(&teifsmu); | ||
1338 | mISDN_FsmFree(&teifsmn); | ||
1339 | mISDN_FsmFree(&deactfsm); | ||
1340 | } | ||
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c new file mode 100644 index 000000000000..b5fabc7019d8 --- /dev/null +++ b/drivers/isdn/mISDN/timerdev.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * | ||
3 | * general timer device for using in ISDN stacks | ||
4 | * | ||
5 | * Author Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
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 | */ | ||
19 | |||
20 | #include <linux/poll.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/mISDNif.h> | ||
26 | |||
27 | static int *debug; | ||
28 | |||
29 | |||
30 | struct mISDNtimerdev { | ||
31 | int next_id; | ||
32 | struct list_head pending; | ||
33 | struct list_head expired; | ||
34 | wait_queue_head_t wait; | ||
35 | u_int work; | ||
36 | spinlock_t lock; /* protect lists */ | ||
37 | }; | ||
38 | |||
39 | struct mISDNtimer { | ||
40 | struct list_head list; | ||
41 | struct mISDNtimerdev *dev; | ||
42 | struct timer_list tl; | ||
43 | int id; | ||
44 | }; | ||
45 | |||
46 | static int | ||
47 | mISDN_open(struct inode *ino, struct file *filep) | ||
48 | { | ||
49 | struct mISDNtimerdev *dev; | ||
50 | |||
51 | if (*debug & DEBUG_TIMER) | ||
52 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
53 | dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL); | ||
54 | if (!dev) | ||
55 | return -ENOMEM; | ||
56 | dev->next_id = 1; | ||
57 | INIT_LIST_HEAD(&dev->pending); | ||
58 | INIT_LIST_HEAD(&dev->expired); | ||
59 | spin_lock_init(&dev->lock); | ||
60 | dev->work = 0; | ||
61 | init_waitqueue_head(&dev->wait); | ||
62 | filep->private_data = dev; | ||
63 | __module_get(THIS_MODULE); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | mISDN_close(struct inode *ino, struct file *filep) | ||
69 | { | ||
70 | struct mISDNtimerdev *dev = filep->private_data; | ||
71 | struct mISDNtimer *timer, *next; | ||
72 | |||
73 | if (*debug & DEBUG_TIMER) | ||
74 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
75 | list_for_each_entry_safe(timer, next, &dev->pending, list) { | ||
76 | del_timer(&timer->tl); | ||
77 | kfree(timer); | ||
78 | } | ||
79 | list_for_each_entry_safe(timer, next, &dev->expired, list) { | ||
80 | kfree(timer); | ||
81 | } | ||
82 | kfree(dev); | ||
83 | module_put(THIS_MODULE); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static ssize_t | ||
88 | mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) | ||
89 | { | ||
90 | struct mISDNtimerdev *dev = filep->private_data; | ||
91 | struct mISDNtimer *timer; | ||
92 | u_long flags; | ||
93 | int ret = 0; | ||
94 | |||
95 | if (*debug & DEBUG_TIMER) | ||
96 | printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, | ||
97 | filep, buf, (int)count, off); | ||
98 | if (*off != filep->f_pos) | ||
99 | return -ESPIPE; | ||
100 | |||
101 | if (list_empty(&dev->expired) && (dev->work == 0)) { | ||
102 | if (filep->f_flags & O_NONBLOCK) | ||
103 | return -EAGAIN; | ||
104 | wait_event_interruptible(dev->wait, (dev->work || | ||
105 | !list_empty(&dev->expired))); | ||
106 | if (signal_pending(current)) | ||
107 | return -ERESTARTSYS; | ||
108 | } | ||
109 | if (count < sizeof(int)) | ||
110 | return -ENOSPC; | ||
111 | if (dev->work) | ||
112 | dev->work = 0; | ||
113 | if (!list_empty(&dev->expired)) { | ||
114 | spin_lock_irqsave(&dev->lock, flags); | ||
115 | timer = (struct mISDNtimer *)dev->expired.next; | ||
116 | list_del(&timer->list); | ||
117 | spin_unlock_irqrestore(&dev->lock, flags); | ||
118 | if (put_user(timer->id, (int *)buf)) | ||
119 | ret = -EFAULT; | ||
120 | else | ||
121 | ret = sizeof(int); | ||
122 | kfree(timer); | ||
123 | } | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static loff_t | ||
128 | mISDN_llseek(struct file *filep, loff_t offset, int orig) | ||
129 | { | ||
130 | return -ESPIPE; | ||
131 | } | ||
132 | |||
133 | static ssize_t | ||
134 | mISDN_write(struct file *filep, const char *buf, size_t count, loff_t *off) | ||
135 | { | ||
136 | return -EOPNOTSUPP; | ||
137 | } | ||
138 | |||
139 | static unsigned int | ||
140 | mISDN_poll(struct file *filep, poll_table *wait) | ||
141 | { | ||
142 | struct mISDNtimerdev *dev = filep->private_data; | ||
143 | unsigned int mask = POLLERR; | ||
144 | |||
145 | if (*debug & DEBUG_TIMER) | ||
146 | printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait); | ||
147 | if (dev) { | ||
148 | poll_wait(filep, &dev->wait, wait); | ||
149 | mask = 0; | ||
150 | if (dev->work || !list_empty(&dev->expired)) | ||
151 | mask |= (POLLIN | POLLRDNORM); | ||
152 | if (*debug & DEBUG_TIMER) | ||
153 | printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, | ||
154 | dev->work, list_empty(&dev->expired)); | ||
155 | } | ||
156 | return mask; | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | dev_expire_timer(struct mISDNtimer *timer) | ||
161 | { | ||
162 | u_long flags; | ||
163 | |||
164 | spin_lock_irqsave(&timer->dev->lock, flags); | ||
165 | list_del(&timer->list); | ||
166 | list_add_tail(&timer->list, &timer->dev->expired); | ||
167 | spin_unlock_irqrestore(&timer->dev->lock, flags); | ||
168 | wake_up_interruptible(&timer->dev->wait); | ||
169 | } | ||
170 | |||
171 | static int | ||
172 | misdn_add_timer(struct mISDNtimerdev *dev, int timeout) | ||
173 | { | ||
174 | int id; | ||
175 | u_long flags; | ||
176 | struct mISDNtimer *timer; | ||
177 | |||
178 | if (!timeout) { | ||
179 | dev->work = 1; | ||
180 | wake_up_interruptible(&dev->wait); | ||
181 | id = 0; | ||
182 | } else { | ||
183 | timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); | ||
184 | if (!timer) | ||
185 | return -ENOMEM; | ||
186 | spin_lock_irqsave(&dev->lock, flags); | ||
187 | timer->id = dev->next_id++; | ||
188 | if (dev->next_id < 0) | ||
189 | dev->next_id = 1; | ||
190 | list_add_tail(&timer->list, &dev->pending); | ||
191 | spin_unlock_irqrestore(&dev->lock, flags); | ||
192 | timer->dev = dev; | ||
193 | timer->tl.data = (long)timer; | ||
194 | timer->tl.function = (void *) dev_expire_timer; | ||
195 | init_timer(&timer->tl); | ||
196 | timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); | ||
197 | add_timer(&timer->tl); | ||
198 | id = timer->id; | ||
199 | } | ||
200 | return id; | ||
201 | } | ||
202 | |||
203 | static int | ||
204 | misdn_del_timer(struct mISDNtimerdev *dev, int id) | ||
205 | { | ||
206 | u_long flags; | ||
207 | struct mISDNtimer *timer; | ||
208 | int ret = 0; | ||
209 | |||
210 | spin_lock_irqsave(&dev->lock, flags); | ||
211 | list_for_each_entry(timer, &dev->pending, list) { | ||
212 | if (timer->id == id) { | ||
213 | list_del_init(&timer->list); | ||
214 | del_timer(&timer->tl); | ||
215 | ret = timer->id; | ||
216 | kfree(timer); | ||
217 | goto unlock; | ||
218 | } | ||
219 | } | ||
220 | unlock: | ||
221 | spin_unlock_irqrestore(&dev->lock, flags); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, | ||
227 | unsigned long arg) | ||
228 | { | ||
229 | struct mISDNtimerdev *dev = filep->private_data; | ||
230 | int id, tout, ret = 0; | ||
231 | |||
232 | |||
233 | if (*debug & DEBUG_TIMER) | ||
234 | printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__, | ||
235 | filep, cmd, arg); | ||
236 | switch (cmd) { | ||
237 | case IMADDTIMER: | ||
238 | if (get_user(tout, (int __user *)arg)) { | ||
239 | ret = -EFAULT; | ||
240 | break; | ||
241 | } | ||
242 | id = misdn_add_timer(dev, tout); | ||
243 | if (*debug & DEBUG_TIMER) | ||
244 | printk(KERN_DEBUG "%s add %d id %d\n", __func__, | ||
245 | tout, id); | ||
246 | if (id < 0) { | ||
247 | ret = id; | ||
248 | break; | ||
249 | } | ||
250 | if (put_user(id, (int __user *)arg)) | ||
251 | ret = -EFAULT; | ||
252 | break; | ||
253 | case IMDELTIMER: | ||
254 | if (get_user(id, (int __user *)arg)) { | ||
255 | ret = -EFAULT; | ||
256 | break; | ||
257 | } | ||
258 | if (*debug & DEBUG_TIMER) | ||
259 | printk(KERN_DEBUG "%s del id %d\n", __func__, id); | ||
260 | id = misdn_del_timer(dev, id); | ||
261 | if (put_user(id, (int __user *)arg)) | ||
262 | ret = -EFAULT; | ||
263 | break; | ||
264 | default: | ||
265 | ret = -EINVAL; | ||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static struct file_operations mISDN_fops = { | ||
271 | .llseek = mISDN_llseek, | ||
272 | .read = mISDN_read, | ||
273 | .write = mISDN_write, | ||
274 | .poll = mISDN_poll, | ||
275 | .ioctl = mISDN_ioctl, | ||
276 | .open = mISDN_open, | ||
277 | .release = mISDN_close, | ||
278 | }; | ||
279 | |||
280 | static struct miscdevice mISDNtimer = { | ||
281 | .minor = MISC_DYNAMIC_MINOR, | ||
282 | .name = "mISDNtimer", | ||
283 | .fops = &mISDN_fops, | ||
284 | }; | ||
285 | |||
286 | int | ||
287 | mISDN_inittimer(int *deb) | ||
288 | { | ||
289 | int err; | ||
290 | |||
291 | debug = deb; | ||
292 | err = misc_register(&mISDNtimer); | ||
293 | if (err) | ||
294 | printk(KERN_WARNING "mISDN: Could not register timer device\n"); | ||
295 | return err; | ||
296 | } | ||
297 | |||
298 | void mISDN_timer_cleanup(void) | ||
299 | { | ||
300 | misc_deregister(&mISDNtimer); | ||
301 | } | ||
diff --git a/include/linux/mISDNdsp.h b/include/linux/mISDNdsp.h new file mode 100644 index 000000000000..6b71d2dce508 --- /dev/null +++ b/include/linux/mISDNdsp.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef __mISDNdsp_H__ | ||
2 | #define __mISDNdsp_H__ | ||
3 | |||
4 | struct mISDN_dsp_element_arg { | ||
5 | char *name; | ||
6 | char *def; | ||
7 | char *desc; | ||
8 | }; | ||
9 | |||
10 | struct mISDN_dsp_element { | ||
11 | char *name; | ||
12 | void *(*new)(const char *arg); | ||
13 | void (*free)(void *p); | ||
14 | void (*process_tx)(void *p, unsigned char *data, int len); | ||
15 | void (*process_rx)(void *p, unsigned char *data, int len); | ||
16 | int num_args; | ||
17 | struct mISDN_dsp_element_arg | ||
18 | *args; | ||
19 | }; | ||
20 | |||
21 | extern int mISDN_dsp_element_register(struct mISDN_dsp_element *elem); | ||
22 | extern void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem); | ||
23 | |||
24 | struct dsp_features { | ||
25 | int hfc_id; /* unique id to identify the chip (or -1) */ | ||
26 | int hfc_dtmf; /* set if HFCmulti card supports dtmf */ | ||
27 | int hfc_loops; /* set if card supports tone loops */ | ||
28 | int hfc_echocanhw; /* set if card supports echocancelation*/ | ||
29 | int pcm_id; /* unique id to identify the pcm bus (or -1) */ | ||
30 | int pcm_slots; /* number of slots on the pcm bus */ | ||
31 | int pcm_banks; /* number of IO banks of pcm bus */ | ||
32 | int unclocked; /* data is not clocked (has jitter/loss) */ | ||
33 | int unordered; /* data is unordered (packets have index) */ | ||
34 | }; | ||
35 | |||
36 | #endif | ||
37 | |||
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h new file mode 100644 index 000000000000..e794dfb87504 --- /dev/null +++ b/include/linux/mISDNhw.h | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Basic declarations for the mISDN HW channels | ||
6 | * | ||
7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
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 | */ | ||
19 | |||
20 | #ifndef MISDNHW_H | ||
21 | #define MISDNHW_H | ||
22 | #include <linux/mISDNif.h> | ||
23 | #include <linux/timer.h> | ||
24 | |||
25 | /* | ||
26 | * HW DEBUG 0xHHHHGGGG | ||
27 | * H - hardware driver specific bits | ||
28 | * G - for all drivers | ||
29 | */ | ||
30 | |||
31 | #define DEBUG_HW 0x00000001 | ||
32 | #define DEBUG_HW_OPEN 0x00000002 | ||
33 | #define DEBUG_HW_DCHANNEL 0x00000100 | ||
34 | #define DEBUG_HW_DFIFO 0x00000200 | ||
35 | #define DEBUG_HW_BCHANNEL 0x00001000 | ||
36 | #define DEBUG_HW_BFIFO 0x00002000 | ||
37 | |||
38 | #define MAX_DFRAME_LEN_L1 300 | ||
39 | #define MAX_MON_FRAME 32 | ||
40 | #define MAX_LOG_SPACE 2048 | ||
41 | #define MISDN_COPY_SIZE 32 | ||
42 | |||
43 | /* channel->Flags bit field */ | ||
44 | #define FLG_TX_BUSY 0 /* tx_buf in use */ | ||
45 | #define FLG_TX_NEXT 1 /* next_skb in use */ | ||
46 | #define FLG_L1_BUSY 2 /* L1 is permanent busy */ | ||
47 | #define FLG_L2_ACTIVATED 3 /* activated from L2 */ | ||
48 | #define FLG_OPEN 5 /* channel is in use */ | ||
49 | #define FLG_ACTIVE 6 /* channel is activated */ | ||
50 | #define FLG_BUSY_TIMER 7 | ||
51 | /* channel type */ | ||
52 | #define FLG_DCHANNEL 8 /* channel is D-channel */ | ||
53 | #define FLG_BCHANNEL 9 /* channel is B-channel */ | ||
54 | #define FLG_ECHANNEL 10 /* channel is E-channel */ | ||
55 | #define FLG_TRANSPARENT 12 /* channel use transparent data */ | ||
56 | #define FLG_HDLC 13 /* channel use hdlc data */ | ||
57 | #define FLG_L2DATA 14 /* channel use L2 DATA primitivs */ | ||
58 | #define FLG_ORIGIN 15 /* channel is on origin site */ | ||
59 | /* channel specific stuff */ | ||
60 | /* arcofi specific */ | ||
61 | #define FLG_ARCOFI_TIMER 16 | ||
62 | #define FLG_ARCOFI_ERROR 17 | ||
63 | /* isar specific */ | ||
64 | #define FLG_INITIALIZED 16 | ||
65 | #define FLG_DLEETX 17 | ||
66 | #define FLG_LASTDLE 18 | ||
67 | #define FLG_FIRST 19 | ||
68 | #define FLG_LASTDATA 20 | ||
69 | #define FLG_NMD_DATA 21 | ||
70 | #define FLG_FTI_RUN 22 | ||
71 | #define FLG_LL_OK 23 | ||
72 | #define FLG_LL_CONN 24 | ||
73 | #define FLG_DTMFSEND 25 | ||
74 | |||
75 | /* workq events */ | ||
76 | #define FLG_RECVQUEUE 30 | ||
77 | #define FLG_PHCHANGE 31 | ||
78 | |||
79 | #define schedule_event(s, ev) do { \ | ||
80 | test_and_set_bit(ev, &((s)->Flags)); \ | ||
81 | schedule_work(&((s)->workq)); \ | ||
82 | } while (0) | ||
83 | |||
84 | struct dchannel { | ||
85 | struct mISDNdevice dev; | ||
86 | u_long Flags; | ||
87 | struct work_struct workq; | ||
88 | void (*phfunc) (struct dchannel *); | ||
89 | u_int state; | ||
90 | void *l1; | ||
91 | /* HW access */ | ||
92 | u_char (*read_reg) (void *, u_char); | ||
93 | void (*write_reg) (void *, u_char, u_char); | ||
94 | void (*read_fifo) (void *, u_char *, int); | ||
95 | void (*write_fifo) (void *, u_char *, int); | ||
96 | void *hw; | ||
97 | int slot; /* multiport card channel slot */ | ||
98 | struct timer_list timer; | ||
99 | /* receive data */ | ||
100 | struct sk_buff *rx_skb; | ||
101 | int maxlen; | ||
102 | /* send data */ | ||
103 | struct sk_buff_head squeue; | ||
104 | struct sk_buff_head rqueue; | ||
105 | struct sk_buff *tx_skb; | ||
106 | int tx_idx; | ||
107 | int debug; | ||
108 | /* statistics */ | ||
109 | int err_crc; | ||
110 | int err_tx; | ||
111 | int err_rx; | ||
112 | }; | ||
113 | |||
114 | typedef int (dchannel_l1callback)(struct dchannel *, u_int); | ||
115 | extern int create_l1(struct dchannel *, dchannel_l1callback *); | ||
116 | |||
117 | /* private L1 commands */ | ||
118 | #define INFO0 0x8002 | ||
119 | #define INFO1 0x8102 | ||
120 | #define INFO2 0x8202 | ||
121 | #define INFO3_P8 0x8302 | ||
122 | #define INFO3_P10 0x8402 | ||
123 | #define INFO4_P8 0x8502 | ||
124 | #define INFO4_P10 0x8602 | ||
125 | #define LOSTFRAMING 0x8702 | ||
126 | #define ANYSIGNAL 0x8802 | ||
127 | #define HW_POWERDOWN 0x8902 | ||
128 | #define HW_RESET_REQ 0x8a02 | ||
129 | #define HW_POWERUP_REQ 0x8b02 | ||
130 | #define HW_DEACT_REQ 0x8c02 | ||
131 | #define HW_ACTIVATE_REQ 0x8e02 | ||
132 | #define HW_D_NOBLOCKED 0x8f02 | ||
133 | #define HW_RESET_IND 0x9002 | ||
134 | #define HW_POWERUP_IND 0x9102 | ||
135 | #define HW_DEACT_IND 0x9202 | ||
136 | #define HW_ACTIVATE_IND 0x9302 | ||
137 | #define HW_DEACT_CNF 0x9402 | ||
138 | #define HW_TESTLOOP 0x9502 | ||
139 | #define HW_TESTRX_RAW 0x9602 | ||
140 | #define HW_TESTRX_HDLC 0x9702 | ||
141 | #define HW_TESTRX_OFF 0x9802 | ||
142 | |||
143 | struct layer1; | ||
144 | extern int l1_event(struct layer1 *, u_int); | ||
145 | |||
146 | |||
147 | struct bchannel { | ||
148 | struct mISDNchannel ch; | ||
149 | int nr; | ||
150 | u_long Flags; | ||
151 | struct work_struct workq; | ||
152 | u_int state; | ||
153 | /* HW access */ | ||
154 | u_char (*read_reg) (void *, u_char); | ||
155 | void (*write_reg) (void *, u_char, u_char); | ||
156 | void (*read_fifo) (void *, u_char *, int); | ||
157 | void (*write_fifo) (void *, u_char *, int); | ||
158 | void *hw; | ||
159 | int slot; /* multiport card channel slot */ | ||
160 | struct timer_list timer; | ||
161 | /* receive data */ | ||
162 | struct sk_buff *rx_skb; | ||
163 | int maxlen; | ||
164 | /* send data */ | ||
165 | struct sk_buff *next_skb; | ||
166 | struct sk_buff *tx_skb; | ||
167 | struct sk_buff_head rqueue; | ||
168 | int rcount; | ||
169 | int tx_idx; | ||
170 | int debug; | ||
171 | /* statistics */ | ||
172 | int err_crc; | ||
173 | int err_tx; | ||
174 | int err_rx; | ||
175 | }; | ||
176 | |||
177 | extern int mISDN_initdchannel(struct dchannel *, int, void *); | ||
178 | extern int mISDN_initbchannel(struct bchannel *, int); | ||
179 | extern int mISDN_freedchannel(struct dchannel *); | ||
180 | extern int mISDN_freebchannel(struct bchannel *); | ||
181 | extern void queue_ch_frame(struct mISDNchannel *, u_int, | ||
182 | int, struct sk_buff *); | ||
183 | extern int dchannel_senddata(struct dchannel *, struct sk_buff *); | ||
184 | extern int bchannel_senddata(struct bchannel *, struct sk_buff *); | ||
185 | extern void recv_Dchannel(struct dchannel *); | ||
186 | extern void recv_Bchannel(struct bchannel *); | ||
187 | extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *); | ||
188 | extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); | ||
189 | extern void confirm_Bsend(struct bchannel *bch); | ||
190 | extern int get_next_bframe(struct bchannel *); | ||
191 | extern int get_next_dframe(struct dchannel *); | ||
192 | |||
193 | #endif | ||
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h new file mode 100644 index 000000000000..5c948f337817 --- /dev/null +++ b/include/linux/mISDNif.h | |||
@@ -0,0 +1,487 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Author Karsten Keil <kkeil@novell.com> | ||
4 | * | ||
5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
6 | * | ||
7 | * This code is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE | ||
9 | * version 2.1 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This code is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU LESSER GENERAL PUBLIC LICENSE for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef mISDNIF_H | ||
19 | #define mISDNIF_H | ||
20 | |||
21 | #include <stdarg.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/socket.h> | ||
25 | |||
26 | /* | ||
27 | * ABI Version 32 bit | ||
28 | * | ||
29 | * <8 bit> Major version | ||
30 | * - changed if any interface become backwards incompatible | ||
31 | * | ||
32 | * <8 bit> Minor version | ||
33 | * - changed if any interface is extended but backwards compatible | ||
34 | * | ||
35 | * <16 bit> Release number | ||
36 | * - should be incremented on every checkin | ||
37 | */ | ||
38 | #define MISDN_MAJOR_VERSION 1 | ||
39 | #define MISDN_MINOR_VERSION 0 | ||
40 | #define MISDN_RELEASE 18 | ||
41 | |||
42 | /* primitives for information exchange | ||
43 | * generell format | ||
44 | * <16 bit 0 > | ||
45 | * <8 bit command> | ||
46 | * BIT 8 = 1 LAYER private | ||
47 | * BIT 7 = 1 answer | ||
48 | * BIT 6 = 1 DATA | ||
49 | * <8 bit target layer mask> | ||
50 | * | ||
51 | * Layer = 00 is reserved for general commands | ||
52 | Layer = 01 L2 -> HW | ||
53 | Layer = 02 HW -> L2 | ||
54 | Layer = 04 L3 -> L2 | ||
55 | Layer = 08 L2 -> L3 | ||
56 | * Layer = FF is reserved for broadcast commands | ||
57 | */ | ||
58 | |||
59 | #define MISDN_CMDMASK 0xff00 | ||
60 | #define MISDN_LAYERMASK 0x00ff | ||
61 | |||
62 | /* generell commands */ | ||
63 | #define OPEN_CHANNEL 0x0100 | ||
64 | #define CLOSE_CHANNEL 0x0200 | ||
65 | #define CONTROL_CHANNEL 0x0300 | ||
66 | #define CHECK_DATA 0x0400 | ||
67 | |||
68 | /* layer 2 -> layer 1 */ | ||
69 | #define PH_ACTIVATE_REQ 0x0101 | ||
70 | #define PH_DEACTIVATE_REQ 0x0201 | ||
71 | #define PH_DATA_REQ 0x2001 | ||
72 | #define MPH_ACTIVATE_REQ 0x0501 | ||
73 | #define MPH_DEACTIVATE_REQ 0x0601 | ||
74 | #define MPH_INFORMATION_REQ 0x0701 | ||
75 | #define PH_CONTROL_REQ 0x0801 | ||
76 | |||
77 | /* layer 1 -> layer 2 */ | ||
78 | #define PH_ACTIVATE_IND 0x0102 | ||
79 | #define PH_ACTIVATE_CNF 0x4102 | ||
80 | #define PH_DEACTIVATE_IND 0x0202 | ||
81 | #define PH_DEACTIVATE_CNF 0x4202 | ||
82 | #define PH_DATA_IND 0x2002 | ||
83 | #define MPH_ACTIVATE_IND 0x0502 | ||
84 | #define MPH_DEACTIVATE_IND 0x0602 | ||
85 | #define MPH_INFORMATION_IND 0x0702 | ||
86 | #define PH_DATA_CNF 0x6002 | ||
87 | #define PH_CONTROL_IND 0x0802 | ||
88 | #define PH_CONTROL_CNF 0x4802 | ||
89 | |||
90 | /* layer 3 -> layer 2 */ | ||
91 | #define DL_ESTABLISH_REQ 0x1004 | ||
92 | #define DL_RELEASE_REQ 0x1104 | ||
93 | #define DL_DATA_REQ 0x3004 | ||
94 | #define DL_UNITDATA_REQ 0x3104 | ||
95 | #define DL_INFORMATION_REQ 0x0004 | ||
96 | |||
97 | /* layer 2 -> layer 3 */ | ||
98 | #define DL_ESTABLISH_IND 0x1008 | ||
99 | #define DL_ESTABLISH_CNF 0x5008 | ||
100 | #define DL_RELEASE_IND 0x1108 | ||
101 | #define DL_RELEASE_CNF 0x5108 | ||
102 | #define DL_DATA_IND 0x3008 | ||
103 | #define DL_UNITDATA_IND 0x3108 | ||
104 | #define DL_INFORMATION_IND 0x0008 | ||
105 | |||
106 | /* intern layer 2 managment */ | ||
107 | #define MDL_ASSIGN_REQ 0x1804 | ||
108 | #define MDL_ASSIGN_IND 0x1904 | ||
109 | #define MDL_REMOVE_REQ 0x1A04 | ||
110 | #define MDL_REMOVE_IND 0x1B04 | ||
111 | #define MDL_STATUS_UP_IND 0x1C04 | ||
112 | #define MDL_STATUS_DOWN_IND 0x1D04 | ||
113 | #define MDL_STATUS_UI_IND 0x1E04 | ||
114 | #define MDL_ERROR_IND 0x1F04 | ||
115 | #define MDL_ERROR_RSP 0x5F04 | ||
116 | |||
117 | /* DL_INFORMATION_IND types */ | ||
118 | #define DL_INFO_L2_CONNECT 0x0001 | ||
119 | #define DL_INFO_L2_REMOVED 0x0002 | ||
120 | |||
121 | /* PH_CONTROL types */ | ||
122 | /* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */ | ||
123 | #define DTMF_TONE_VAL 0x2000 | ||
124 | #define DTMF_TONE_MASK 0x007F | ||
125 | #define DTMF_TONE_START 0x2100 | ||
126 | #define DTMF_TONE_STOP 0x2200 | ||
127 | #define DTMF_HFC_COEF 0x4000 | ||
128 | #define DSP_CONF_JOIN 0x2403 | ||
129 | #define DSP_CONF_SPLIT 0x2404 | ||
130 | #define DSP_RECEIVE_OFF 0x2405 | ||
131 | #define DSP_RECEIVE_ON 0x2406 | ||
132 | #define DSP_ECHO_ON 0x2407 | ||
133 | #define DSP_ECHO_OFF 0x2408 | ||
134 | #define DSP_MIX_ON 0x2409 | ||
135 | #define DSP_MIX_OFF 0x240a | ||
136 | #define DSP_DELAY 0x240b | ||
137 | #define DSP_JITTER 0x240c | ||
138 | #define DSP_TXDATA_ON 0x240d | ||
139 | #define DSP_TXDATA_OFF 0x240e | ||
140 | #define DSP_TX_DEJITTER 0x240f | ||
141 | #define DSP_TX_DEJ_OFF 0x2410 | ||
142 | #define DSP_TONE_PATT_ON 0x2411 | ||
143 | #define DSP_TONE_PATT_OFF 0x2412 | ||
144 | #define DSP_VOL_CHANGE_TX 0x2413 | ||
145 | #define DSP_VOL_CHANGE_RX 0x2414 | ||
146 | #define DSP_BF_ENABLE_KEY 0x2415 | ||
147 | #define DSP_BF_DISABLE 0x2416 | ||
148 | #define DSP_BF_ACCEPT 0x2416 | ||
149 | #define DSP_BF_REJECT 0x2417 | ||
150 | #define DSP_PIPELINE_CFG 0x2418 | ||
151 | #define HFC_VOL_CHANGE_TX 0x2601 | ||
152 | #define HFC_VOL_CHANGE_RX 0x2602 | ||
153 | #define HFC_SPL_LOOP_ON 0x2603 | ||
154 | #define HFC_SPL_LOOP_OFF 0x2604 | ||
155 | |||
156 | /* DSP_TONE_PATT_ON parameter */ | ||
157 | #define TONE_OFF 0x0000 | ||
158 | #define TONE_GERMAN_DIALTONE 0x0001 | ||
159 | #define TONE_GERMAN_OLDDIALTONE 0x0002 | ||
160 | #define TONE_AMERICAN_DIALTONE 0x0003 | ||
161 | #define TONE_GERMAN_DIALPBX 0x0004 | ||
162 | #define TONE_GERMAN_OLDDIALPBX 0x0005 | ||
163 | #define TONE_AMERICAN_DIALPBX 0x0006 | ||
164 | #define TONE_GERMAN_RINGING 0x0007 | ||
165 | #define TONE_GERMAN_OLDRINGING 0x0008 | ||
166 | #define TONE_AMERICAN_RINGPBX 0x000b | ||
167 | #define TONE_GERMAN_RINGPBX 0x000c | ||
168 | #define TONE_GERMAN_OLDRINGPBX 0x000d | ||
169 | #define TONE_AMERICAN_RINGING 0x000e | ||
170 | #define TONE_GERMAN_BUSY 0x000f | ||
171 | #define TONE_GERMAN_OLDBUSY 0x0010 | ||
172 | #define TONE_AMERICAN_BUSY 0x0011 | ||
173 | #define TONE_GERMAN_HANGUP 0x0012 | ||
174 | #define TONE_GERMAN_OLDHANGUP 0x0013 | ||
175 | #define TONE_AMERICAN_HANGUP 0x0014 | ||
176 | #define TONE_SPECIAL_INFO 0x0015 | ||
177 | #define TONE_GERMAN_GASSENBESETZT 0x0016 | ||
178 | #define TONE_GERMAN_AUFSCHALTTON 0x0016 | ||
179 | |||
180 | /* MPH_INFORMATION_IND */ | ||
181 | #define L1_SIGNAL_LOS_OFF 0x0010 | ||
182 | #define L1_SIGNAL_LOS_ON 0x0011 | ||
183 | #define L1_SIGNAL_AIS_OFF 0x0012 | ||
184 | #define L1_SIGNAL_AIS_ON 0x0013 | ||
185 | #define L1_SIGNAL_RDI_OFF 0x0014 | ||
186 | #define L1_SIGNAL_RDI_ON 0x0015 | ||
187 | #define L1_SIGNAL_SLIP_RX 0x0020 | ||
188 | #define L1_SIGNAL_SLIP_TX 0x0021 | ||
189 | |||
190 | /* | ||
191 | * protocol ids | ||
192 | * D channel 1-31 | ||
193 | * B channel 33 - 63 | ||
194 | */ | ||
195 | |||
196 | #define ISDN_P_NONE 0 | ||
197 | #define ISDN_P_BASE 0 | ||
198 | #define ISDN_P_TE_S0 0x01 | ||
199 | #define ISDN_P_NT_S0 0x02 | ||
200 | #define ISDN_P_TE_E1 0x03 | ||
201 | #define ISDN_P_NT_E1 0x04 | ||
202 | #define ISDN_P_LAPD_TE 0x10 | ||
203 | #define ISDN_P_LAPD_NT 0x11 | ||
204 | |||
205 | #define ISDN_P_B_MASK 0x1f | ||
206 | #define ISDN_P_B_START 0x20 | ||
207 | |||
208 | #define ISDN_P_B_RAW 0x21 | ||
209 | #define ISDN_P_B_HDLC 0x22 | ||
210 | #define ISDN_P_B_X75SLP 0x23 | ||
211 | #define ISDN_P_B_L2DTMF 0x24 | ||
212 | #define ISDN_P_B_L2DSP 0x25 | ||
213 | #define ISDN_P_B_L2DSPHDLC 0x26 | ||
214 | |||
215 | #define OPTION_L2_PMX 1 | ||
216 | #define OPTION_L2_PTP 2 | ||
217 | #define OPTION_L2_FIXEDTEI 3 | ||
218 | #define OPTION_L2_CLEANUP 4 | ||
219 | |||
220 | /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ | ||
221 | #define MISDN_MAX_IDLEN 20 | ||
222 | |||
223 | struct mISDNhead { | ||
224 | unsigned int prim; | ||
225 | unsigned int id; | ||
226 | } __attribute__((packed)); | ||
227 | |||
228 | #define MISDN_HEADER_LEN sizeof(struct mISDNhead) | ||
229 | #define MAX_DATA_SIZE 2048 | ||
230 | #define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN) | ||
231 | #define MAX_DFRAME_LEN 260 | ||
232 | |||
233 | #define MISDN_ID_ADDR_MASK 0xFFFF | ||
234 | #define MISDN_ID_TEI_MASK 0xFF00 | ||
235 | #define MISDN_ID_SAPI_MASK 0x00FF | ||
236 | #define MISDN_ID_TEI_ANY 0x7F00 | ||
237 | |||
238 | #define MISDN_ID_ANY 0xFFFF | ||
239 | #define MISDN_ID_NONE 0xFFFE | ||
240 | |||
241 | #define GROUP_TEI 127 | ||
242 | #define TEI_SAPI 63 | ||
243 | #define CTRL_SAPI 0 | ||
244 | |||
245 | #define MISDN_CHMAP_SIZE 4 | ||
246 | |||
247 | #define SOL_MISDN 0 | ||
248 | |||
249 | struct sockaddr_mISDN { | ||
250 | sa_family_t family; | ||
251 | unsigned char dev; | ||
252 | unsigned char channel; | ||
253 | unsigned char sapi; | ||
254 | unsigned char tei; | ||
255 | }; | ||
256 | |||
257 | /* timer device ioctl */ | ||
258 | #define IMADDTIMER _IOR('I', 64, int) | ||
259 | #define IMDELTIMER _IOR('I', 65, int) | ||
260 | /* socket ioctls */ | ||
261 | #define IMGETVERSION _IOR('I', 66, int) | ||
262 | #define IMGETCOUNT _IOR('I', 67, int) | ||
263 | #define IMGETDEVINFO _IOR('I', 68, int) | ||
264 | #define IMCTRLREQ _IOR('I', 69, int) | ||
265 | #define IMCLEAR_L2 _IOR('I', 70, int) | ||
266 | |||
267 | struct mISDNversion { | ||
268 | unsigned char major; | ||
269 | unsigned char minor; | ||
270 | unsigned short release; | ||
271 | }; | ||
272 | |||
273 | struct mISDN_devinfo { | ||
274 | u_int id; | ||
275 | u_int Dprotocols; | ||
276 | u_int Bprotocols; | ||
277 | u_int protocol; | ||
278 | u_long channelmap[MISDN_CHMAP_SIZE]; | ||
279 | u_int nrbchan; | ||
280 | char name[MISDN_MAX_IDLEN]; | ||
281 | }; | ||
282 | |||
283 | /* CONTROL_CHANNEL parameters */ | ||
284 | #define MISDN_CTRL_GETOP 0x0000 | ||
285 | #define MISDN_CTRL_LOOP 0x0001 | ||
286 | #define MISDN_CTRL_CONNECT 0x0002 | ||
287 | #define MISDN_CTRL_DISCONNECT 0x0004 | ||
288 | #define MISDN_CTRL_PCMCONNECT 0x0010 | ||
289 | #define MISDN_CTRL_PCMDISCONNECT 0x0020 | ||
290 | #define MISDN_CTRL_SETPEER 0x0040 | ||
291 | #define MISDN_CTRL_UNSETPEER 0x0080 | ||
292 | #define MISDN_CTRL_RX_OFF 0x0100 | ||
293 | #define MISDN_CTRL_HW_FEATURES_OP 0x2000 | ||
294 | #define MISDN_CTRL_HW_FEATURES 0x2001 | ||
295 | #define MISDN_CTRL_HFC_OP 0x4000 | ||
296 | #define MISDN_CTRL_HFC_PCM_CONN 0x4001 | ||
297 | #define MISDN_CTRL_HFC_PCM_DISC 0x4002 | ||
298 | #define MISDN_CTRL_HFC_CONF_JOIN 0x4003 | ||
299 | #define MISDN_CTRL_HFC_CONF_SPLIT 0x4004 | ||
300 | #define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005 | ||
301 | #define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 | ||
302 | #define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 | ||
303 | #define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 | ||
304 | |||
305 | |||
306 | /* socket options */ | ||
307 | #define MISDN_TIME_STAMP 0x0001 | ||
308 | |||
309 | struct mISDN_ctrl_req { | ||
310 | int op; | ||
311 | int channel; | ||
312 | int p1; | ||
313 | int p2; | ||
314 | }; | ||
315 | |||
316 | /* muxer options */ | ||
317 | #define MISDN_OPT_ALL 1 | ||
318 | #define MISDN_OPT_TEIMGR 2 | ||
319 | |||
320 | #ifdef __KERNEL__ | ||
321 | #include <linux/list.h> | ||
322 | #include <linux/skbuff.h> | ||
323 | #include <linux/net.h> | ||
324 | #include <net/sock.h> | ||
325 | #include <linux/completion.h> | ||
326 | |||
327 | #define DEBUG_CORE 0x000000ff | ||
328 | #define DEBUG_CORE_FUNC 0x00000002 | ||
329 | #define DEBUG_SOCKET 0x00000004 | ||
330 | #define DEBUG_MANAGER 0x00000008 | ||
331 | #define DEBUG_SEND_ERR 0x00000010 | ||
332 | #define DEBUG_MSG_THREAD 0x00000020 | ||
333 | #define DEBUG_QUEUE_FUNC 0x00000040 | ||
334 | #define DEBUG_L1 0x0000ff00 | ||
335 | #define DEBUG_L1_FSM 0x00000200 | ||
336 | #define DEBUG_L2 0x00ff0000 | ||
337 | #define DEBUG_L2_FSM 0x00020000 | ||
338 | #define DEBUG_L2_CTRL 0x00040000 | ||
339 | #define DEBUG_L2_RECV 0x00080000 | ||
340 | #define DEBUG_L2_TEI 0x00100000 | ||
341 | #define DEBUG_L2_TEIFSM 0x00200000 | ||
342 | #define DEBUG_TIMER 0x01000000 | ||
343 | |||
344 | #define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) | ||
345 | #define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) | ||
346 | #define mISDN_HEAD_ID(s) (((struct mISDNhead *)&s->cb[0])->id) | ||
347 | |||
348 | /* socket states */ | ||
349 | #define MISDN_OPEN 1 | ||
350 | #define MISDN_BOUND 2 | ||
351 | #define MISDN_CLOSED 3 | ||
352 | |||
353 | struct mISDNchannel; | ||
354 | struct mISDNdevice; | ||
355 | struct mISDNstack; | ||
356 | |||
357 | struct channel_req { | ||
358 | u_int protocol; | ||
359 | struct sockaddr_mISDN adr; | ||
360 | struct mISDNchannel *ch; | ||
361 | }; | ||
362 | |||
363 | typedef int (ctrl_func_t)(struct mISDNchannel *, u_int, void *); | ||
364 | typedef int (send_func_t)(struct mISDNchannel *, struct sk_buff *); | ||
365 | typedef int (create_func_t)(struct channel_req *); | ||
366 | |||
367 | struct Bprotocol { | ||
368 | struct list_head list; | ||
369 | char *name; | ||
370 | u_int Bprotocols; | ||
371 | create_func_t *create; | ||
372 | }; | ||
373 | |||
374 | struct mISDNchannel { | ||
375 | struct list_head list; | ||
376 | u_int protocol; | ||
377 | u_int nr; | ||
378 | u_long opt; | ||
379 | u_int addr; | ||
380 | struct mISDNstack *st; | ||
381 | struct mISDNchannel *peer; | ||
382 | send_func_t *send; | ||
383 | send_func_t *recv; | ||
384 | ctrl_func_t *ctrl; | ||
385 | }; | ||
386 | |||
387 | struct mISDN_sock_list { | ||
388 | struct hlist_head head; | ||
389 | rwlock_t lock; | ||
390 | }; | ||
391 | |||
392 | struct mISDN_sock { | ||
393 | struct sock sk; | ||
394 | struct mISDNchannel ch; | ||
395 | u_int cmask; | ||
396 | struct mISDNdevice *dev; | ||
397 | }; | ||
398 | |||
399 | |||
400 | |||
401 | struct mISDNdevice { | ||
402 | struct mISDNchannel D; | ||
403 | u_int id; | ||
404 | char name[MISDN_MAX_IDLEN]; | ||
405 | u_int Dprotocols; | ||
406 | u_int Bprotocols; | ||
407 | u_int nrbchan; | ||
408 | u_long channelmap[MISDN_CHMAP_SIZE]; | ||
409 | struct list_head bchannels; | ||
410 | struct mISDNchannel *teimgr; | ||
411 | struct device dev; | ||
412 | }; | ||
413 | |||
414 | struct mISDNstack { | ||
415 | u_long status; | ||
416 | struct mISDNdevice *dev; | ||
417 | struct task_struct *thread; | ||
418 | struct completion *notify; | ||
419 | wait_queue_head_t workq; | ||
420 | struct sk_buff_head msgq; | ||
421 | struct list_head layer2; | ||
422 | struct mISDNchannel *layer1; | ||
423 | struct mISDNchannel own; | ||
424 | struct mutex lmutex; /* protect lists */ | ||
425 | struct mISDN_sock_list l1sock; | ||
426 | #ifdef MISDN_MSG_STATS | ||
427 | u_int msg_cnt; | ||
428 | u_int sleep_cnt; | ||
429 | u_int stopped_cnt; | ||
430 | #endif | ||
431 | }; | ||
432 | |||
433 | /* global alloc/queue dunctions */ | ||
434 | |||
435 | static inline struct sk_buff * | ||
436 | mI_alloc_skb(unsigned int len, gfp_t gfp_mask) | ||
437 | { | ||
438 | struct sk_buff *skb; | ||
439 | |||
440 | skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask); | ||
441 | if (likely(skb)) | ||
442 | skb_reserve(skb, MISDN_HEADER_LEN); | ||
443 | return skb; | ||
444 | } | ||
445 | |||
446 | static inline struct sk_buff * | ||
447 | _alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask) | ||
448 | { | ||
449 | struct sk_buff *skb = mI_alloc_skb(len, gfp_mask); | ||
450 | struct mISDNhead *hh; | ||
451 | |||
452 | if (!skb) | ||
453 | return NULL; | ||
454 | if (len) | ||
455 | memcpy(skb_put(skb, len), dp, len); | ||
456 | hh = mISDN_HEAD_P(skb); | ||
457 | hh->prim = prim; | ||
458 | hh->id = id; | ||
459 | return skb; | ||
460 | } | ||
461 | |||
462 | static inline void | ||
463 | _queue_data(struct mISDNchannel *ch, u_int prim, | ||
464 | u_int id, u_int len, void *dp, gfp_t gfp_mask) | ||
465 | { | ||
466 | struct sk_buff *skb; | ||
467 | |||
468 | if (!ch->peer) | ||
469 | return; | ||
470 | skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask); | ||
471 | if (!skb) | ||
472 | return; | ||
473 | if (ch->recv(ch->peer, skb)) | ||
474 | dev_kfree_skb(skb); | ||
475 | } | ||
476 | |||
477 | /* global register/unregister functions */ | ||
478 | |||
479 | extern int mISDN_register_device(struct mISDNdevice *, char *name); | ||
480 | extern void mISDN_unregister_device(struct mISDNdevice *); | ||
481 | extern int mISDN_register_Bprotocol(struct Bprotocol *); | ||
482 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); | ||
483 | |||
484 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); | ||
485 | |||
486 | #endif /* __KERNEL__ */ | ||
487 | #endif /* mISDNIF_H */ | ||
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c3b1761aba26..ffe479ba0779 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -1832,7 +1832,13 @@ | |||
1832 | #define PCI_DEVICE_ID_MOXA_C320 0x3200 | 1832 | #define PCI_DEVICE_ID_MOXA_C320 0x3200 |
1833 | 1833 | ||
1834 | #define PCI_VENDOR_ID_CCD 0x1397 | 1834 | #define PCI_VENDOR_ID_CCD 0x1397 |
1835 | #define PCI_DEVICE_ID_CCD_HFC4S 0x08B4 | ||
1836 | #define PCI_SUBDEVICE_ID_CCD_PMX2S 0x1234 | ||
1837 | #define PCI_DEVICE_ID_CCD_HFC8S 0x16B8 | ||
1835 | #define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 | 1838 | #define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 |
1839 | #define PCI_DEVICE_ID_CCD_HFCE1 0x30B1 | ||
1840 | #define PCI_SUBDEVICE_ID_CCD_SPD4S 0x3136 | ||
1841 | #define PCI_SUBDEVICE_ID_CCD_SPDE1 0x3137 | ||
1836 | #define PCI_DEVICE_ID_CCD_B000 0xb000 | 1842 | #define PCI_DEVICE_ID_CCD_B000 0xb000 |
1837 | #define PCI_DEVICE_ID_CCD_B006 0xb006 | 1843 | #define PCI_DEVICE_ID_CCD_B006 0xb006 |
1838 | #define PCI_DEVICE_ID_CCD_B007 0xb007 | 1844 | #define PCI_DEVICE_ID_CCD_B007 0xb007 |
@@ -1842,8 +1848,32 @@ | |||
1842 | #define PCI_DEVICE_ID_CCD_B00B 0xb00b | 1848 | #define PCI_DEVICE_ID_CCD_B00B 0xb00b |
1843 | #define PCI_DEVICE_ID_CCD_B00C 0xb00c | 1849 | #define PCI_DEVICE_ID_CCD_B00C 0xb00c |
1844 | #define PCI_DEVICE_ID_CCD_B100 0xb100 | 1850 | #define PCI_DEVICE_ID_CCD_B100 0xb100 |
1851 | #define PCI_SUBDEVICE_ID_CCD_IOB4ST 0xB520 | ||
1852 | #define PCI_SUBDEVICE_ID_CCD_IOB8STR 0xB521 | ||
1853 | #define PCI_SUBDEVICE_ID_CCD_IOB8ST 0xB522 | ||
1854 | #define PCI_SUBDEVICE_ID_CCD_IOB1E1 0xB523 | ||
1855 | #define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540 | ||
1856 | #define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550 | ||
1857 | #define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552 | ||
1858 | #define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560 | ||
1859 | #define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562 | ||
1860 | #define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563 | ||
1861 | #define PCI_SUBDEVICE_ID_CCD_BNE1D 0xB564 | ||
1862 | #define PCI_SUBDEVICE_ID_CCD_BNE1DP 0xB565 | ||
1863 | #define PCI_SUBDEVICE_ID_CCD_BN2S 0xB566 | ||
1864 | #define PCI_SUBDEVICE_ID_CCD_BN1SM 0xB567 | ||
1865 | #define PCI_SUBDEVICE_ID_CCD_BN4SM 0xB568 | ||
1866 | #define PCI_SUBDEVICE_ID_CCD_BN2SM 0xB569 | ||
1867 | #define PCI_SUBDEVICE_ID_CCD_BNE1M 0xB56A | ||
1868 | #define PCI_SUBDEVICE_ID_CCD_BN8SP 0xB56B | ||
1869 | #define PCI_SUBDEVICE_ID_CCD_HFC4S 0xB620 | ||
1870 | #define PCI_SUBDEVICE_ID_CCD_HFC8S 0xB622 | ||
1845 | #define PCI_DEVICE_ID_CCD_B700 0xb700 | 1871 | #define PCI_DEVICE_ID_CCD_B700 0xb700 |
1846 | #define PCI_DEVICE_ID_CCD_B701 0xb701 | 1872 | #define PCI_DEVICE_ID_CCD_B701 0xb701 |
1873 | #define PCI_SUBDEVICE_ID_CCD_HFCE1 0xC523 | ||
1874 | #define PCI_SUBDEVICE_ID_CCD_OV2S 0xE884 | ||
1875 | #define PCI_SUBDEVICE_ID_CCD_OV4S 0xE888 | ||
1876 | #define PCI_SUBDEVICE_ID_CCD_OV8S 0xE998 | ||
1847 | 1877 | ||
1848 | #define PCI_VENDOR_ID_EXAR 0x13a8 | 1878 | #define PCI_VENDOR_ID_EXAR 0x13a8 |
1849 | #define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 | 1879 | #define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 |
@@ -2523,6 +2553,9 @@ | |||
2523 | 2553 | ||
2524 | #define PCI_VENDOR_ID_3COM_2 0xa727 | 2554 | #define PCI_VENDOR_ID_3COM_2 0xa727 |
2525 | 2555 | ||
2556 | #define PCI_VENDOR_ID_DIGIUM 0xd161 | ||
2557 | #define PCI_DEVICE_ID_DIGIUM_HFC4S 0xb410 | ||
2558 | |||
2526 | #define PCI_SUBVENDOR_ID_EXSYS 0xd84d | 2559 | #define PCI_SUBVENDOR_ID_EXSYS 0xd84d |
2527 | #define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 | 2560 | #define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 |
2528 | #define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055 | 2561 | #define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055 |
diff --git a/include/linux/socket.h b/include/linux/socket.h index 950af631e7fb..dc5086fe7736 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
@@ -189,7 +189,8 @@ struct ucred { | |||
189 | #define AF_BLUETOOTH 31 /* Bluetooth sockets */ | 189 | #define AF_BLUETOOTH 31 /* Bluetooth sockets */ |
190 | #define AF_IUCV 32 /* IUCV sockets */ | 190 | #define AF_IUCV 32 /* IUCV sockets */ |
191 | #define AF_RXRPC 33 /* RxRPC sockets */ | 191 | #define AF_RXRPC 33 /* RxRPC sockets */ |
192 | #define AF_MAX 34 /* For now.. */ | 192 | #define AF_ISDN 34 /* mISDN sockets */ |
193 | #define AF_MAX 35 /* For now.. */ | ||
193 | 194 | ||
194 | /* Protocol families, same as address families. */ | 195 | /* Protocol families, same as address families. */ |
195 | #define PF_UNSPEC AF_UNSPEC | 196 | #define PF_UNSPEC AF_UNSPEC |
@@ -225,6 +226,7 @@ struct ucred { | |||
225 | #define PF_BLUETOOTH AF_BLUETOOTH | 226 | #define PF_BLUETOOTH AF_BLUETOOTH |
226 | #define PF_IUCV AF_IUCV | 227 | #define PF_IUCV AF_IUCV |
227 | #define PF_RXRPC AF_RXRPC | 228 | #define PF_RXRPC AF_RXRPC |
229 | #define PF_ISDN AF_ISDN | ||
228 | #define PF_MAX AF_MAX | 230 | #define PF_MAX AF_MAX |
229 | 231 | ||
230 | /* Maximum queue length specifiable by listen. */ | 232 | /* Maximum queue length specifiable by listen. */ |