diff options
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfc_multi.h | 3 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfcmulti.c | 45 | ||||
-rw-r--r-- | drivers/isdn/mISDN/Makefile | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/clock.c | 216 | ||||
-rw-r--r-- | drivers/isdn/mISDN/core.c | 1 | ||||
-rw-r--r-- | drivers/isdn/mISDN/core.h | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_cmx.c | 40 | ||||
-rw-r--r-- | include/linux/mISDNif.h | 17 |
8 files changed, 294 insertions, 32 deletions
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 4aa6a8b41f50..663b77f578be 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h | |||
@@ -197,6 +197,9 @@ struct hfc_multi { | |||
197 | 197 | ||
198 | spinlock_t lock; /* the lock */ | 198 | spinlock_t lock; /* the lock */ |
199 | 199 | ||
200 | struct mISDNclock *iclock; /* isdn clock support */ | ||
201 | int iclock_on; | ||
202 | |||
200 | /* | 203 | /* |
201 | * the channel index is counted from 0, regardless where the channel | 204 | * the channel index is counted from 0, regardless where the channel |
202 | * is located on the hfc-channel. | 205 | * is located on the hfc-channel. |
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 3fc2e9d95341..592db93105f9 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
@@ -133,6 +133,12 @@ | |||
133 | * Give the value of the clock control register (A_ST_CLK_DLY) | 133 | * Give the value of the clock control register (A_ST_CLK_DLY) |
134 | * of the S/T interfaces in TE mode. | 134 | * of the S/T interfaces in TE mode. |
135 | * This register is needed for the TBR3 certification, so don't change it. | 135 | * This register is needed for the TBR3 certification, so don't change it. |
136 | * | ||
137 | * clock: | ||
138 | * NOTE: only one clockdelay_te value must be given once | ||
139 | * Selects interface with clock source for mISDN and applications. | ||
140 | * Set to card number starting with 1. Set to -1 to disable. | ||
141 | * By default, the first card is used as clock source. | ||
136 | */ | 142 | */ |
137 | 143 | ||
138 | /* | 144 | /* |
@@ -190,12 +196,13 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; | |||
190 | */ | 196 | */ |
191 | 197 | ||
192 | static uint type[MAX_CARDS]; | 198 | static uint type[MAX_CARDS]; |
193 | static uint pcm[MAX_CARDS]; | 199 | static int pcm[MAX_CARDS]; |
194 | static uint dslot[MAX_CARDS]; | 200 | static int dslot[MAX_CARDS]; |
195 | static uint iomode[MAX_CARDS]; | 201 | static uint iomode[MAX_CARDS]; |
196 | static uint port[MAX_PORTS]; | 202 | static uint port[MAX_PORTS]; |
197 | static uint debug; | 203 | static uint debug; |
198 | static uint poll; | 204 | static uint poll; |
205 | static int clock; | ||
199 | static uint timer; | 206 | static uint timer; |
200 | static uint clockdelay_te = CLKDEL_TE; | 207 | static uint clockdelay_te = CLKDEL_TE; |
201 | static uint clockdelay_nt = CLKDEL_NT; | 208 | static uint clockdelay_nt = CLKDEL_NT; |
@@ -207,12 +214,13 @@ MODULE_LICENSE("GPL"); | |||
207 | MODULE_VERSION(HFC_MULTI_VERSION); | 214 | MODULE_VERSION(HFC_MULTI_VERSION); |
208 | module_param(debug, uint, S_IRUGO | S_IWUSR); | 215 | module_param(debug, uint, S_IRUGO | S_IWUSR); |
209 | module_param(poll, uint, S_IRUGO | S_IWUSR); | 216 | module_param(poll, uint, S_IRUGO | S_IWUSR); |
217 | module_param(clock, int, S_IRUGO | S_IWUSR); | ||
210 | module_param(timer, uint, S_IRUGO | S_IWUSR); | 218 | module_param(timer, uint, S_IRUGO | S_IWUSR); |
211 | module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); | 219 | module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); |
212 | module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); | 220 | module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); |
213 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | 221 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); |
214 | module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR); | 222 | module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); |
215 | module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR); | 223 | module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); |
216 | module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); | 224 | module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); |
217 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | 225 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); |
218 | 226 | ||
@@ -2629,6 +2637,7 @@ hfcmulti_interrupt(int intno, void *dev_id) | |||
2629 | iqcnt = 0; | 2637 | iqcnt = 0; |
2630 | } | 2638 | } |
2631 | #endif | 2639 | #endif |
2640 | |||
2632 | if (!r_irq_statech && | 2641 | if (!r_irq_statech && |
2633 | !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | | 2642 | !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | |
2634 | V_MISC_IRQSTA | V_FR_IRQSTA))) { | 2643 | V_MISC_IRQSTA | V_FR_IRQSTA))) { |
@@ -2683,11 +2692,13 @@ hfcmulti_interrupt(int intno, void *dev_id) | |||
2683 | plxsd_checksync(hc, 0); | 2692 | plxsd_checksync(hc, 0); |
2684 | } | 2693 | } |
2685 | } | 2694 | } |
2686 | if (r_irq_misc & V_TI_IRQ) | 2695 | if (r_irq_misc & V_TI_IRQ) { |
2696 | if (hc->iclock_on) | ||
2697 | mISDN_clock_update(hc->iclock, poll, NULL); | ||
2687 | handle_timer_irq(hc); | 2698 | handle_timer_irq(hc); |
2699 | } | ||
2688 | 2700 | ||
2689 | if (r_irq_misc & V_DTMF_IRQ) { | 2701 | if (r_irq_misc & V_DTMF_IRQ) { |
2690 | /* -> DTMF IRQ */ | ||
2691 | hfcmulti_dtmf(hc); | 2702 | hfcmulti_dtmf(hc); |
2692 | } | 2703 | } |
2693 | if (r_irq_misc & V_IRQ_PROC) { | 2704 | if (r_irq_misc & V_IRQ_PROC) { |
@@ -4075,6 +4086,15 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | |||
4075 | return err; | 4086 | return err; |
4076 | } | 4087 | } |
4077 | 4088 | ||
4089 | static int | ||
4090 | clockctl(void *priv, int enable) | ||
4091 | { | ||
4092 | struct hfc_multi *hc = priv; | ||
4093 | |||
4094 | hc->iclock_on = enable; | ||
4095 | return 0; | ||
4096 | } | ||
4097 | |||
4078 | /* | 4098 | /* |
4079 | * initialize the card | 4099 | * initialize the card |
4080 | */ | 4100 | */ |
@@ -4489,10 +4509,14 @@ release_card(struct hfc_multi *hc) | |||
4489 | printk(KERN_WARNING "%s: release card (%d) entered\n", | 4509 | printk(KERN_WARNING "%s: release card (%d) entered\n", |
4490 | __func__, hc->id); | 4510 | __func__, hc->id); |
4491 | 4511 | ||
4512 | /* unregister clock source */ | ||
4513 | if (hc->iclock) | ||
4514 | mISDN_unregister_clock(hc->iclock); | ||
4515 | |||
4516 | /* disable irq */ | ||
4492 | spin_lock_irqsave(&hc->lock, flags); | 4517 | spin_lock_irqsave(&hc->lock, flags); |
4493 | disable_hwirq(hc); | 4518 | disable_hwirq(hc); |
4494 | spin_unlock_irqrestore(&hc->lock, flags); | 4519 | spin_unlock_irqrestore(&hc->lock, flags); |
4495 | |||
4496 | udelay(1000); | 4520 | udelay(1000); |
4497 | 4521 | ||
4498 | /* dimm leds */ | 4522 | /* dimm leds */ |
@@ -5003,6 +5027,10 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
5003 | list_add_tail(&hc->list, &HFClist); | 5027 | list_add_tail(&hc->list, &HFClist); |
5004 | spin_unlock_irqrestore(&HFClock, flags); | 5028 | spin_unlock_irqrestore(&HFClock, flags); |
5005 | 5029 | ||
5030 | /* use as clock source */ | ||
5031 | if (clock == HFC_cnt + 1) | ||
5032 | hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); | ||
5033 | |||
5006 | /* initialize hardware */ | 5034 | /* initialize hardware */ |
5007 | ret_err = init_card(hc); | 5035 | ret_err = init_card(hc); |
5008 | if (ret_err) { | 5036 | if (ret_err) { |
@@ -5273,6 +5301,9 @@ HFCmulti_init(void) | |||
5273 | 5301 | ||
5274 | } | 5302 | } |
5275 | 5303 | ||
5304 | if (!clock) | ||
5305 | clock = 1; | ||
5306 | |||
5276 | err = pci_register_driver(&hfcmultipci_driver); | 5307 | err = pci_register_driver(&hfcmultipci_driver); |
5277 | if (err < 0) { | 5308 | if (err < 0) { |
5278 | printk(KERN_ERR "error registering pci driver: %x\n", err); | 5309 | printk(KERN_ERR "error registering pci driver: %x\n", err); |
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile index 1cb5e633cf75..0a6bd2a9e730 100644 --- a/drivers/isdn/mISDN/Makefile +++ b/drivers/isdn/mISDN/Makefile | |||
@@ -8,6 +8,6 @@ obj-$(CONFIG_MISDN_L1OIP) += l1oip.o | |||
8 | 8 | ||
9 | # multi objects | 9 | # multi objects |
10 | 10 | ||
11 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o | 11 | mISDN_core-objs := core.o fsm.o socket.o clock.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 | 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 | 13 | l1oip-objs := l1oip_core.o l1oip_codec.o |
diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c new file mode 100644 index 000000000000..44d9c3d5d33d --- /dev/null +++ b/drivers/isdn/mISDN/clock.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu> | ||
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 | * Quick API description: | ||
14 | * | ||
15 | * A clock source registers using mISDN_register_clock: | ||
16 | * name = text string to name clock source | ||
17 | * priority = value to priorize clock sources (0 = default) | ||
18 | * ctl = callback function to enable/disable clock source | ||
19 | * priv = private pointer of clock source | ||
20 | * return = pointer to clock source structure; | ||
21 | * | ||
22 | * Note: Callback 'ctl' can be called before mISDN_register_clock returns! | ||
23 | * Also it can be called during mISDN_unregister_clock. | ||
24 | * | ||
25 | * A clock source calls mISDN_clock_update with given samples elapsed, if | ||
26 | * enabled. If function call is delayed, tv must be set with the timestamp | ||
27 | * of the actual event. | ||
28 | * | ||
29 | * A clock source unregisters using mISDN_unregister_clock. | ||
30 | * | ||
31 | * To get current clock, call mISDN_clock_get. The signed short value | ||
32 | * counts the number of samples since. Time since last clock event is added. | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/types.h> | ||
37 | #include <linux/stddef.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/mISDNif.h> | ||
40 | #include "core.h" | ||
41 | |||
42 | static u_int *debug; | ||
43 | static LIST_HEAD(iclock_list); | ||
44 | DEFINE_RWLOCK(iclock_lock); | ||
45 | u16 iclock_count; /* counter of last clock */ | ||
46 | struct timeval iclock_tv; /* time stamp of last clock */ | ||
47 | int iclock_tv_valid; /* already received one timestamp */ | ||
48 | struct mISDNclock *iclock_current; | ||
49 | |||
50 | void | ||
51 | mISDN_init_clock(u_int *dp) | ||
52 | { | ||
53 | debug = dp; | ||
54 | do_gettimeofday(&iclock_tv); | ||
55 | } | ||
56 | |||
57 | static void | ||
58 | select_iclock(void) | ||
59 | { | ||
60 | struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL; | ||
61 | int pri = -128; | ||
62 | |||
63 | list_for_each_entry(iclock, &iclock_list, list) { | ||
64 | if (iclock->pri > pri) { | ||
65 | pri = iclock->pri; | ||
66 | bestclock = iclock; | ||
67 | } | ||
68 | if (iclock_current == iclock) | ||
69 | lastclock = iclock; | ||
70 | } | ||
71 | if (lastclock && bestclock != lastclock) { | ||
72 | /* last used clock source still exists but changes, disable */ | ||
73 | if (*debug & DEBUG_CLOCK) | ||
74 | printk(KERN_DEBUG "Old clock source '%s' disable.\n", | ||
75 | lastclock->name); | ||
76 | lastclock->ctl(lastclock->priv, 0); | ||
77 | } | ||
78 | if (bestclock && bestclock != iclock_current) { | ||
79 | /* new clock source selected, enable */ | ||
80 | if (*debug & DEBUG_CLOCK) | ||
81 | printk(KERN_DEBUG "New clock source '%s' enable.\n", | ||
82 | bestclock->name); | ||
83 | bestclock->ctl(bestclock->priv, 1); | ||
84 | } | ||
85 | if (bestclock != iclock_current) { | ||
86 | /* no clock received yet */ | ||
87 | iclock_tv_valid = 0; | ||
88 | } | ||
89 | iclock_current = bestclock; | ||
90 | } | ||
91 | |||
92 | struct mISDNclock | ||
93 | *mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv) | ||
94 | { | ||
95 | u_long flags; | ||
96 | struct mISDNclock *iclock; | ||
97 | |||
98 | if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) | ||
99 | printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri); | ||
100 | iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC); | ||
101 | if (!iclock) { | ||
102 | printk(KERN_ERR "%s: No memory for clock entry.\n", __func__); | ||
103 | return NULL; | ||
104 | } | ||
105 | strncpy(iclock->name, name, sizeof(iclock->name)-1); | ||
106 | iclock->pri = pri; | ||
107 | iclock->priv = priv; | ||
108 | iclock->ctl = ctl; | ||
109 | write_lock_irqsave(&iclock_lock, flags); | ||
110 | list_add_tail(&iclock->list, &iclock_list); | ||
111 | select_iclock(); | ||
112 | write_unlock_irqrestore(&iclock_lock, flags); | ||
113 | return iclock; | ||
114 | } | ||
115 | EXPORT_SYMBOL(mISDN_register_clock); | ||
116 | |||
117 | void | ||
118 | mISDN_unregister_clock(struct mISDNclock *iclock) | ||
119 | { | ||
120 | u_long flags; | ||
121 | |||
122 | if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) | ||
123 | printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name, | ||
124 | iclock->pri); | ||
125 | write_lock_irqsave(&iclock_lock, flags); | ||
126 | if (iclock_current == iclock) { | ||
127 | if (*debug & DEBUG_CLOCK) | ||
128 | printk(KERN_DEBUG | ||
129 | "Current clock source '%s' unregisters.\n", | ||
130 | iclock->name); | ||
131 | iclock->ctl(iclock->priv, 0); | ||
132 | } | ||
133 | list_del(&iclock->list); | ||
134 | select_iclock(); | ||
135 | write_unlock_irqrestore(&iclock_lock, flags); | ||
136 | } | ||
137 | EXPORT_SYMBOL(mISDN_unregister_clock); | ||
138 | |||
139 | void | ||
140 | mISDN_clock_update(struct mISDNclock *iclock, int samples, struct timeval *tv) | ||
141 | { | ||
142 | u_long flags; | ||
143 | struct timeval tv_now; | ||
144 | time_t elapsed_sec; | ||
145 | int elapsed_8000th; | ||
146 | |||
147 | write_lock_irqsave(&iclock_lock, flags); | ||
148 | if (iclock_current != iclock) { | ||
149 | printk(KERN_ERR "%s: '%s' sends us clock updates, but we do " | ||
150 | "listen to '%s'. This is a bug!\n", __func__, | ||
151 | iclock->name, | ||
152 | iclock_current ? iclock_current->name : "nothing"); | ||
153 | iclock->ctl(iclock->priv, 0); | ||
154 | write_unlock_irqrestore(&iclock_lock, flags); | ||
155 | return; | ||
156 | } | ||
157 | if (iclock_tv_valid) { | ||
158 | /* increment sample counter by given samples */ | ||
159 | iclock_count += samples; | ||
160 | if (tv) { /* tv must be set, if function call is delayed */ | ||
161 | iclock_tv.tv_sec = tv->tv_sec; | ||
162 | iclock_tv.tv_usec = tv->tv_usec; | ||
163 | } else | ||
164 | do_gettimeofday(&iclock_tv); | ||
165 | } else { | ||
166 | /* calc elapsed time by system clock */ | ||
167 | if (tv) { /* tv must be set, if function call is delayed */ | ||
168 | tv_now.tv_sec = tv->tv_sec; | ||
169 | tv_now.tv_usec = tv->tv_usec; | ||
170 | } else | ||
171 | do_gettimeofday(&tv_now); | ||
172 | elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec; | ||
173 | elapsed_8000th = (tv_now.tv_usec / 125) | ||
174 | - (iclock_tv.tv_usec / 125); | ||
175 | if (elapsed_8000th < 0) { | ||
176 | elapsed_sec -= 1; | ||
177 | elapsed_8000th += 8000; | ||
178 | } | ||
179 | /* add elapsed time to counter and set new timestamp */ | ||
180 | iclock_count += elapsed_sec * 8000 + elapsed_8000th; | ||
181 | iclock_tv.tv_sec = tv_now.tv_sec; | ||
182 | iclock_tv.tv_usec = tv_now.tv_usec; | ||
183 | iclock_tv_valid = 1; | ||
184 | if (*debug & DEBUG_CLOCK) | ||
185 | printk("Received first clock from source '%s'.\n", | ||
186 | iclock_current ? iclock_current->name : "nothing"); | ||
187 | } | ||
188 | write_unlock_irqrestore(&iclock_lock, flags); | ||
189 | } | ||
190 | EXPORT_SYMBOL(mISDN_clock_update); | ||
191 | |||
192 | unsigned short | ||
193 | mISDN_clock_get(void) | ||
194 | { | ||
195 | u_long flags; | ||
196 | struct timeval tv_now; | ||
197 | time_t elapsed_sec; | ||
198 | int elapsed_8000th; | ||
199 | u16 count; | ||
200 | |||
201 | read_lock_irqsave(&iclock_lock, flags); | ||
202 | /* calc elapsed time by system clock */ | ||
203 | do_gettimeofday(&tv_now); | ||
204 | elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec; | ||
205 | elapsed_8000th = (tv_now.tv_usec / 125) - (iclock_tv.tv_usec / 125); | ||
206 | if (elapsed_8000th < 0) { | ||
207 | elapsed_sec -= 1; | ||
208 | elapsed_8000th += 8000; | ||
209 | } | ||
210 | /* add elapsed time to counter */ | ||
211 | count = iclock_count + elapsed_sec * 8000 + elapsed_8000th; | ||
212 | read_unlock_irqrestore(&iclock_lock, flags); | ||
213 | return count; | ||
214 | } | ||
215 | EXPORT_SYMBOL(mISDN_clock_get); | ||
216 | |||
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 43fd97b0fe42..9116f54def2c 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c | |||
@@ -199,6 +199,7 @@ mISDNInit(void) | |||
199 | 199 | ||
200 | printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", | 200 | printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", |
201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); | 201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); |
202 | mISDN_init_clock(&debug); | ||
202 | mISDN_initstack(&debug); | 203 | mISDN_initstack(&debug); |
203 | err = mISDN_inittimer(&debug); | 204 | err = mISDN_inittimer(&debug); |
204 | if (err) | 205 | if (err) |
diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h index 7da7233b4c1a..7ac2f81a812b 100644 --- a/drivers/isdn/mISDN/core.h +++ b/drivers/isdn/mISDN/core.h | |||
@@ -74,4 +74,6 @@ extern void l1_cleanup(void); | |||
74 | extern int Isdnl2_Init(u_int *); | 74 | extern int Isdnl2_Init(u_int *); |
75 | extern void Isdnl2_cleanup(void); | 75 | extern void Isdnl2_cleanup(void); |
76 | 76 | ||
77 | extern void mISDN_init_clock(u_int *); | ||
78 | |||
77 | #endif | 79 | #endif |
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 04dbb407f7a0..efe4c7430e6d 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c | |||
@@ -1557,13 +1557,11 @@ send_packet: | |||
1557 | schedule_work(&dsp->workq); | 1557 | schedule_work(&dsp->workq); |
1558 | } | 1558 | } |
1559 | 1559 | ||
1560 | static u32 samplecount; | 1560 | static u32 jittercount; /* counter for jitter check */; |
1561 | struct timer_list dsp_spl_tl; | 1561 | struct timer_list dsp_spl_tl; |
1562 | u32 dsp_spl_jiffies; /* calculate the next time to fire */ | 1562 | u32 dsp_spl_jiffies; /* calculate the next time to fire */ |
1563 | #ifdef UNUSED | 1563 | static u16 dsp_count; /* last sample count */ |
1564 | static u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ | 1564 | static int dsp_count_valid ; /* if we have last sample count */ |
1565 | #endif /* UNUSED */ | ||
1566 | static struct timeval dsp_start_tv; /* time at start of calculation */ | ||
1567 | 1565 | ||
1568 | void | 1566 | void |
1569 | dsp_cmx_send(void *arg) | 1567 | dsp_cmx_send(void *arg) |
@@ -1577,38 +1575,32 @@ dsp_cmx_send(void *arg) | |||
1577 | int r, rr; | 1575 | int r, rr; |
1578 | int jittercheck = 0, delay, i; | 1576 | int jittercheck = 0, delay, i; |
1579 | u_long flags; | 1577 | u_long flags; |
1580 | struct timeval tv; | 1578 | u16 length, count; |
1581 | u32 elapsed; | ||
1582 | s16 length; | ||
1583 | 1579 | ||
1584 | /* lock */ | 1580 | /* lock */ |
1585 | spin_lock_irqsave(&dsp_lock, flags); | 1581 | spin_lock_irqsave(&dsp_lock, flags); |
1586 | 1582 | ||
1587 | if (!dsp_start_tv.tv_sec) { | 1583 | if (!dsp_count_valid) { |
1588 | do_gettimeofday(&dsp_start_tv); | 1584 | dsp_count = mISDN_clock_get(); |
1589 | length = dsp_poll; | 1585 | length = dsp_poll; |
1586 | dsp_count_valid = 1; | ||
1590 | } else { | 1587 | } else { |
1591 | do_gettimeofday(&tv); | 1588 | count = mISDN_clock_get(); |
1592 | elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000) | 1589 | length = count - dsp_count; |
1593 | + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125)); | 1590 | dsp_count = count; |
1594 | dsp_start_tv.tv_sec = tv.tv_sec; | ||
1595 | dsp_start_tv.tv_usec = tv.tv_usec; | ||
1596 | length = elapsed; | ||
1597 | } | 1591 | } |
1598 | if (length > MAX_POLL + 100) | 1592 | if (length > MAX_POLL + 100) |
1599 | length = MAX_POLL + 100; | 1593 | length = MAX_POLL + 100; |
1600 | /* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n", | 1594 | /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */ |
1601 | length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16, | ||
1602 | dsp_poll_diff & 0xffff); | ||
1603 | */ | ||
1604 | 1595 | ||
1605 | /* | 1596 | /* |
1606 | * check if jitter needs to be checked | 1597 | * check if jitter needs to be checked (this is every second) |
1607 | * (this is about every second = 8192 samples) | ||
1608 | */ | 1598 | */ |
1609 | samplecount += length; | 1599 | jittercount += length; |
1610 | if ((samplecount & 8191) < length) | 1600 | if (jittercount >= 8000) { |
1601 | jittercount -= 8000; | ||
1611 | jittercheck = 1; | 1602 | jittercheck = 1; |
1603 | } | ||
1612 | 1604 | ||
1613 | /* loop all members that do not require conference mixing */ | 1605 | /* loop all members that do not require conference mixing */ |
1614 | list_for_each_entry(dsp, &dsp_ilist, list) { | 1606 | list_for_each_entry(dsp, &dsp_ilist, list) { |
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index f75d596c5316..364f1018f0d1 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h | |||
@@ -371,6 +371,7 @@ struct mISDN_ctrl_req { | |||
371 | #define DEBUG_L2_TEI 0x00100000 | 371 | #define DEBUG_L2_TEI 0x00100000 |
372 | #define DEBUG_L2_TEIFSM 0x00200000 | 372 | #define DEBUG_L2_TEIFSM 0x00200000 |
373 | #define DEBUG_TIMER 0x01000000 | 373 | #define DEBUG_TIMER 0x01000000 |
374 | #define DEBUG_CLOCK 0x02000000 | ||
374 | 375 | ||
375 | #define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) | 376 | #define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0]) |
376 | #define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) | 377 | #define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim) |
@@ -384,6 +385,7 @@ struct mISDN_ctrl_req { | |||
384 | struct mISDNchannel; | 385 | struct mISDNchannel; |
385 | struct mISDNdevice; | 386 | struct mISDNdevice; |
386 | struct mISDNstack; | 387 | struct mISDNstack; |
388 | struct mISDNclock; | ||
387 | 389 | ||
388 | struct channel_req { | 390 | struct channel_req { |
389 | u_int protocol; | 391 | u_int protocol; |
@@ -460,6 +462,16 @@ struct mISDNstack { | |||
460 | #endif | 462 | #endif |
461 | }; | 463 | }; |
462 | 464 | ||
465 | typedef int (clockctl_func_t)(void *, int); | ||
466 | |||
467 | struct mISDNclock { | ||
468 | struct list_head list; | ||
469 | char name[64]; | ||
470 | int pri; | ||
471 | clockctl_func_t *ctl; | ||
472 | void *priv; | ||
473 | }; | ||
474 | |||
463 | /* global alloc/queue functions */ | 475 | /* global alloc/queue functions */ |
464 | 476 | ||
465 | static inline struct sk_buff * | 477 | static inline struct sk_buff * |
@@ -510,8 +522,13 @@ extern int mISDN_register_device(struct mISDNdevice *, char *name); | |||
510 | extern void mISDN_unregister_device(struct mISDNdevice *); | 522 | extern void mISDN_unregister_device(struct mISDNdevice *); |
511 | extern int mISDN_register_Bprotocol(struct Bprotocol *); | 523 | extern int mISDN_register_Bprotocol(struct Bprotocol *); |
512 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); | 524 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); |
525 | extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *, | ||
526 | void *); | ||
527 | extern void mISDN_unregister_clock(struct mISDNclock *); | ||
513 | 528 | ||
514 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); | 529 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); |
530 | extern void mISDN_clock_update(struct mISDNclock *, int, struct timeval *); | ||
531 | extern unsigned short mISDN_clock_get(void); | ||
515 | 532 | ||
516 | #endif /* __KERNEL__ */ | 533 | #endif /* __KERNEL__ */ |
517 | #endif /* mISDNIF_H */ | 534 | #endif /* mISDNIF_H */ |