diff options
author | Andreas Eversberg <andreas@eversberg.eu> | 2008-09-06 03:03:46 -0400 |
---|---|---|
committer | Karsten Keil <kkeil@suse.de> | 2009-01-09 16:44:27 -0500 |
commit | 3bd69ad197a4a3d0085a5dc3b5796111bf176b12 (patch) | |
tree | 573d7c81f97ff0eb15f914d43dbf9f393cf00ded /drivers/isdn/mISDN | |
parent | 55a6af9749d6a31e087f304f2ea39db3bb7b3f3e (diff) |
mISDN: Add ISDN sample clock API to mISDN core
Add ISDN sample clock API to mISDN core (new file clock.c)
hfcmulti and mISDNdsp use clock API.
Signed-off-by: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Karsten Keil <kkeil@suse.de>
Diffstat (limited to 'drivers/isdn/mISDN')
-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 |
5 files changed, 236 insertions, 25 deletions
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) { |