pbx.c: Properly parse labels with leading digits
[asterisk/asterisk.git] / res / res_timing_dahdi.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2008, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \author Russell Bryant <russell@digium.com>
22  *
23  * \brief DAHDI timing interface
24  */
25
26 /*** MODULEINFO
27         <depend>dahdi</depend>
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <math.h>
37
38 #include <dahdi/user.h>
39
40 #include "asterisk/module.h"
41 #include "asterisk/timing.h"
42 #include "asterisk/utils.h"
43
44 static void *timing_funcs_handle;
45
46 static void *dahdi_timer_open(void);
47 static void dahdi_timer_close(void *data);
48 static int dahdi_timer_set_rate(void *data, unsigned int rate);
49 static int dahdi_timer_ack(void *data, unsigned int quantity);
50 static int dahdi_timer_enable_continuous(void *data);
51 static int dahdi_timer_disable_continuous(void *data);
52 static enum ast_timer_event dahdi_timer_get_event(void *data);
53 static unsigned int dahdi_timer_get_max_rate(void *data);
54 static int dahdi_timer_fd(void *data);
55
56 static struct ast_timing_interface dahdi_timing = {
57         .name = "DAHDI",
58         .priority = 100,
59         .timer_open = dahdi_timer_open,
60         .timer_close = dahdi_timer_close,
61         .timer_set_rate = dahdi_timer_set_rate,
62         .timer_ack = dahdi_timer_ack,
63         .timer_enable_continuous = dahdi_timer_enable_continuous,
64         .timer_disable_continuous = dahdi_timer_disable_continuous,
65         .timer_get_event = dahdi_timer_get_event,
66         .timer_get_max_rate = dahdi_timer_get_max_rate,
67         .timer_fd = dahdi_timer_fd,
68 };
69
70 struct dahdi_timer {
71         int fd;
72 };
73
74 static void *dahdi_timer_open(void)
75 {
76         struct dahdi_timer *timer;
77
78         if (!(timer = ast_calloc(1, sizeof(*timer)))) {
79                 return NULL;
80         }
81
82         if ((timer->fd = open("/dev/dahdi/timer", O_RDWR)) < 0) {
83                 ast_log(LOG_ERROR, "Failed to create dahdi timer: %s\n", strerror(errno));
84                 ast_free(timer);
85                 return NULL;
86         }
87
88         return timer;
89 }
90
91 static void dahdi_timer_close(void *data)
92 {
93         struct dahdi_timer *timer = data;
94
95         close(timer->fd);
96         ast_free(timer);
97 }
98
99 static int dahdi_timer_set_rate(void *data, unsigned int rate)
100 {
101         struct dahdi_timer *timer = data;
102         int samples;
103
104         /* DAHDI timers are configured using a number of samples,
105          * based on an 8 kHz sample rate. */
106         samples = (unsigned int) roundf((8000.0 / ((float) rate)));
107
108         if (ioctl(timer->fd, DAHDI_TIMERCONFIG, &samples)) {
109                 ast_log(LOG_ERROR, "Failed to configure DAHDI timing fd for %d sample timer ticks\n",
110                         samples);
111                 return -1;
112         }
113
114         return 0;
115 }
116
117 static int dahdi_timer_ack(void *data, unsigned int quantity)
118 {
119         struct dahdi_timer *timer = data;
120
121         return ioctl(timer->fd, DAHDI_TIMERACK, &quantity) ? -1 : 0;
122 }
123
124 static int dahdi_timer_enable_continuous(void *data)
125 {
126         struct dahdi_timer *timer = data;
127         int flags = 1;
128
129         return ioctl(timer->fd, DAHDI_TIMERPING, &flags) ? -1 : 0;
130 }
131
132 static int dahdi_timer_disable_continuous(void *data)
133 {
134         struct dahdi_timer *timer = data;
135         int flags = -1;
136
137         return ioctl(timer->fd, DAHDI_TIMERPONG, &flags) ? -1 : 0;
138 }
139
140 static enum ast_timer_event dahdi_timer_get_event(void *data)
141 {
142         struct dahdi_timer *timer = data;
143         int res;
144         int event;
145
146         res = ioctl(timer->fd, DAHDI_GETEVENT, &event);
147
148         if (res) {
149                 event = DAHDI_EVENT_TIMER_EXPIRED;
150         }
151
152         switch (event) {
153         case DAHDI_EVENT_TIMER_PING:
154                 return AST_TIMING_EVENT_CONTINUOUS;
155         case DAHDI_EVENT_TIMER_EXPIRED:
156         default:
157                 return AST_TIMING_EVENT_EXPIRED;
158         }
159 }
160
161 static unsigned int dahdi_timer_get_max_rate(void *data)
162 {
163         return 1000;
164 }
165
166 static int dahdi_timer_fd(void *data)
167 {
168         struct dahdi_timer *timer = data;
169
170         return timer->fd;
171 }
172
173 #define SEE_TIMING "For more information on Asterisk timing modules, including ways to potentially fix this problem, please see https://wiki.asterisk.org/wiki/display/AST/Timing+Interfaces\n"
174
175 static int dahdi_test_timer(void)
176 {
177         int fd;
178         int x = 160;
179
180         fd = open("/dev/dahdi/timer", O_RDWR);
181
182         if (fd < 0) {
183                 return -1;
184         }
185
186         if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
187                 ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer test failed to set DAHDI_TIMERCONFIG to %d.\n" SEE_TIMING, x);
188                 close(fd);
189                 return -1;
190         }
191
192         if ((x = ast_wait_for_input(fd, 300)) < 0) {
193                 ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer could not be polled during the DAHDI timer test.\n" SEE_TIMING);
194                 close(fd);
195                 return -1;
196         }
197
198         if (!x) {
199                 const char dahdi_timer_error[] = {
200                         "Asterisk has detected a problem with your DAHDI configuration and will shutdown for your protection.  You have options:"
201                         "\n\t1. You only have to compile DAHDI support into Asterisk if you need it.  One option is to recompile without DAHDI support."
202                         "\n\t2. You only have to load DAHDI drivers if you want to take advantage of DAHDI services.  One option is to unload DAHDI modules if you don't need them."
203                         "\n\t3. If you need DAHDI services, you must correctly configure DAHDI."
204                 };
205                 ast_log(LOG_ERROR, "%s\n" SEE_TIMING, dahdi_timer_error);
206                 usleep(100);
207                 close(fd);
208                 return -1;
209         }
210
211         close(fd);
212
213         return 0;
214 }
215
216 static int load_module(void)
217 {
218         if (dahdi_test_timer()) {
219                 return AST_MODULE_LOAD_DECLINE;
220         }
221
222         return (timing_funcs_handle = ast_register_timing_interface(&dahdi_timing)) ?
223                 AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
224 }
225
226 static int unload_module(void)
227 {
228         if (timing_funcs_handle) {
229                 return ast_unregister_timing_interface(timing_funcs_handle);
230         }
231
232         return 0;
233 }
234
235 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "DAHDI Timing Interface",
236         .support_level = AST_MODULE_SUPPORT_CORE,
237         .load = load_module,
238         .unload = unload_module,
239         .load_pri = AST_MODPRI_TIMING,
240 );