38 #include <sys/socket.h>
40 #include <arpa/inet.h>
42 #include <sys/ioctl.h>
44 #ifdef HAVE_LINUX_COMPILER_H
45 #include <linux/compiler.h>
47 #include <linux/telephony.h>
49 #include <linux/version.h>
50 #include <linux/ixjuser.h>
65 #ifdef QTI_PHONEJACK_TJ_PCI
73 #define IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, &x);
75 #define IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, x);
78 #define IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, &x);
81 #define DEFAULT_CALLER_ID "Unknown"
82 #define PHONE_MAX_BUF 480
83 #define DEFAULT_GAIN 0x100
85 static const char tdesc[] =
"Standard Linux Telephony API Driver";
86 static const char config[] =
"phone.conf";
119 #define MODE_DIALTONE 1
120 #define MODE_IMMEDIATE 2
169 .description =
tdesc,
186 .description =
tdesc,
208 ast_debug(1,
"Requested indication %d on channel %s\n", condition, chan->
name);
211 ioctl(p->
fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
213 ioctl(p->
fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
235 if (pvt && pvt->
owner == old)
263 outdigit = digit -
'0';
273 ioctl(p->
fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
275 ioctl(p->
fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
283 ioctl(p->
fd, PHONE_PLAY_TONE, outdigit);
299 memset(&cid, 0,
sizeof(PHONE_CID));
300 snprintf(cid.month,
sizeof(cid.month),
"%02d",(tm.
tm_mon + 1));
301 snprintf(cid.day,
sizeof(cid.day),
"%02d", tm.
tm_mday);
302 snprintf(cid.hour,
sizeof(cid.hour),
"%02d", tm.
tm_hour);
303 snprintf(cid.min,
sizeof(cid.min),
"%02d", tm.
tm_min);
329 char *digit = strchr(dest,
'/');
354 if (ioctl(p->
fd, PHONE_REC_STOP))
356 if (ioctl(p->
fd, PHONE_PLAY_STOP))
358 if (ioctl(p->
fd, PHONE_RING_STOP))
360 if (ioctl(p->
fd, PHONE_CPT_STOP))
365 if (ioctl(p->
fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
366 ast_debug(1,
"ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->
name, strerror(
errno));
370 if (ioctl(p->
fd, PHONE_HOOKSTATE)) {
371 ast_debug(1,
"Got hunghup, giving busy signal\n");
372 ioctl(p->
fd, PHONE_BUSY);
380 memset(p->
ext, 0,
sizeof(p->
ext));
394 ioctl(p->
fd, PHONE_CPT_STOP);
398 ioctl(p->
fd, PHONE_REC_STOP);
401 if (ioctl(p->
fd, PHONE_REC_CODEC, G729)) {
407 ioctl(p->
fd, PHONE_REC_STOP);
410 if (ioctl(p->
fd, PHONE_REC_CODEC, G723_63)) {
416 ioctl(p->
fd, PHONE_REC_STOP);
419 if (ioctl(p->
fd, PHONE_REC_CODEC, LINEAR16)) {
425 ioctl(p->
fd, PHONE_REC_STOP);
428 if (ioctl(p->
fd, PHONE_REC_CODEC, ULAW)) {
434 ioctl(p->
fd, PHONE_REC_STOP);
447 if (ioctl(p->
fd, PHONE_REC_START)) {
452 ioctl(p->
fd, PHONE_SET_TONE_ON_TIME, 300);
453 ioctl(p->
fd, PHONE_SET_TONE_OFF_TIME, 200);
463 if (ioctl(p->
fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK))
464 ast_debug(1,
"ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->
name, strerror(
errno));
466 ast_debug(1,
"Took linejack off hook\n");
476 static char phone_2digit(
char c)
482 else if ((c < 10) && (c >= 0))
492 union telephony_exception phonee;
505 phonee.bytes = ioctl(p->
fd, PHONE_EXCEPTION);
506 if (phonee.bits.dtmf_ready) {
507 ast_debug(1,
"phone_exception(): DTMF\n");
510 digit = ioctl(p->
fd, PHONE_GET_DTMF_ASCII);
515 if (phonee.bits.hookstate) {
517 res = ioctl(p->
fd, PHONE_HOOKSTATE);
519 ast_debug(1,
"New hookstate: %d\n", res);
535 if (phonee.bits.pstn_ring)
537 if (phonee.bits.caller_id) {
540 if (phonee.bits.pstn_wink)
570 if (
errno == EAGAIN) {
582 switch(p->
buf[0] & 0x3) {
621 res = write(p->
fd, p->
obuf, frlen);
643 int length = strlen(text);
684 ioctl(p->
fd, PHONE_PLAY_STOP);
685 ioctl(p->
fd, PHONE_REC_STOP);
686 if (ioctl(p->
fd, PHONE_PLAY_CODEC, G729)) {
690 if (ioctl(p->
fd, PHONE_REC_CODEC, G729)) {
707 ioctl(p->
fd, PHONE_PLAY_STOP);
708 ioctl(p->
fd, PHONE_REC_STOP);
709 if (ioctl(p->
fd, PHONE_PLAY_CODEC, G723_63)) {
713 if (ioctl(p->
fd, PHONE_REC_CODEC, G723_63)) {
730 ioctl(p->
fd, PHONE_PLAY_STOP);
731 ioctl(p->
fd, PHONE_REC_STOP);
732 if (ioctl(p->
fd, PHONE_PLAY_CODEC, LINEAR16)) {
736 if (ioctl(p->
fd, PHONE_REC_CODEC, LINEAR16)) {
749 ioctl(p->
fd, PHONE_PLAY_STOP);
750 ioctl(p->
fd, PHONE_REC_STOP);
751 if (ioctl(p->
fd, PHONE_PLAY_CODEC, ULAW)) {
755 if (ioctl(p->
fd, PHONE_REC_CODEC, ULAW)) {
768 ioctl(p->
fd, PHONE_PLAY_STOP);
769 ioctl(p->
fd, PHONE_REC_STOP);
789 ioctl(p->
fd, PHONE_REC_DEPTH, 3);
790 ioctl(p->
fd, PHONE_PLAY_DEPTH, 3);
791 if (ioctl(p->
fd, PHONE_PLAY_START)) {
795 if (ioctl(p->
fd, PHONE_REC_START)) {
803 while(sofar < frame->datalen) {
805 expected = frame->
datalen - sofar;
806 if (maxfr < expected)
812 memcpy(tmpbuf, frame->
data.
ptr, 4);
820 #if __BYTE_ORDER == __BIG_ENDIAN
826 if (res != expected) {
851 struct phone_codec_data queried_codec;
852 tmp =
ast_channel_alloc(1, state, i->
cid_num, i->
cid_name,
"", i->
ext, i->
context, linkedid, 0,
"Phone/%s", i->
dev + 5);
858 ioctl(i->
fd, PHONE_QUERY_CODEC, &queried_codec) == 0) {
859 if (queried_codec.type == LINEAR16)
862 tmp->rawwriteformat =
867 tmp->rawwriteformat =
884 strcpy(tmp->exten,
"s");
891 tmp->caller.ani.number.valid = 1;
899 ioctl(tmp->fds[0], PHONE_RINGBACK);
917 res = read(i->
fd, buf,
sizeof(buf));
927 char digit[2] = {0 , 0};
928 union telephony_exception phonee;
933 phonee.bytes = ioctl(i->
fd, PHONE_EXCEPTION);
934 if (phonee.bits.dtmf_ready) {
935 digit[0] = ioctl(i->
fd, PHONE_GET_DTMF_ASCII);
937 ioctl(i->
fd, PHONE_PLAY_STOP);
938 ioctl(i->
fd, PHONE_REC_STOP);
939 ioctl(i->
fd, PHONE_CPT_STOP);
942 strncat(i->
ext, digit,
sizeof(i->
ext) - strlen(i->
ext) - 1);
944 !(phonee.bytes = ioctl(i->
fd, PHONE_EXCEPTION)) ||
945 !phonee.bits.dtmf_ready) &&
960 ioctl(i->
fd, PHONE_BUSY);
969 if (phonee.bits.hookstate) {
970 offhook = ioctl(i->
fd, PHONE_HOOKSTATE);
980 ioctl(i->
fd, PHONE_PLAY_STOP);
981 ioctl(i->
fd, PHONE_PLAY_CODEC, ULAW);
982 ioctl(i->
fd, PHONE_PLAY_START);
990 ioctl(i->
fd, PHONE_DIALTONE);
995 memset(i->
ext, 0,
sizeof(i->
ext));
998 ioctl(i->
fd, PHONE_CPT_STOP);
1001 ioctl(i->
fd, PHONE_PLAY_STOP);
1002 ioctl(i->
fd, PHONE_REC_STOP);
1007 if (phonee.bits.pstn_ring) {
1011 if (phonee.bits.caller_id)
1019 struct pollfd *fds = NULL;
1020 int nfds = 0, inuse_fds = 0, res;
1024 struct timeval tv = { 0, 0 };
1044 if (inuse_fds == nfds) {
1045 void *tmp =
ast_realloc(fds, (nfds + 1) *
sizeof(*fds));
1053 fds[inuse_fds].fd = i->
fd;
1054 fds[inuse_fds].events = POLLIN | POLLERR;
1055 fds[inuse_fds].revents = 0;
1063 if (write(i->
fd,
DialTone + tonepos, 240) != 240) {
1086 res =
ast_poll(fds, inuse_fds, -1);
1110 for (j = 0; j < inuse_fds; j++) {
1111 if (fds[j].fd == i->
fd) {
1117 if (j == inuse_fds) {
1121 if (fds[j].revents & POLLIN) {
1127 if (fds[j].revents & POLLERR) {
1148 if (monitor_thread == pthread_self()) {
1160 while (pthread_kill(monitor_thread, SIGURG) == 0)
1162 pthread_join(monitor_thread, NULL);
1184 tmp->
fd = open(iface, O_RDWR);
1191 if (ioctl(tmp->
fd, IXJCTL_PORT, PORT_PSTN)) {
1192 ast_debug(1,
"Unable to set port to PSTN\n");
1195 if (ioctl(tmp->
fd, IXJCTL_PORT, PORT_POTS))
1197 ast_debug(1,
"Unable to set port to POTS\n");
1199 ioctl(tmp->
fd, PHONE_PLAY_STOP);
1200 ioctl(tmp->
fd, PHONE_REC_STOP);
1201 ioctl(tmp->
fd, PHONE_RING_STOP);
1202 ioctl(tmp->
fd, PHONE_CPT_STOP);
1203 if (ioctl(tmp->
fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
1204 ast_debug(1,
"ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(
errno));
1205 if (echocancel != AEC_OFF)
1206 ioctl(tmp->
fd, IXJCTL_AEC_START, echocancel);
1207 if (silencesupression)
1213 flags = fcntl(tmp->
fd, F_GETFL);
1214 fcntl(tmp->
fd, F_SETFL, flags | O_NONBLOCK);
1219 memset(tmp->
ext, 0,
sizeof(tmp->
ext));
1230 ioctl(tmp->
fd, PHONE_PLAY_VOLUME, tmp->
txgain);
1232 ioctl(tmp->
fd, PHONE_REC_VOLUME, tmp->
rxgain);
1253 size_t length = strlen(p->
dev + 5);
1254 if (strncmp(name, p->
dev + 5, length) == 0 &&
1255 !isalnum(name[length])) {
1285 if (sscanf(value,
"%30f", &gain) != 1)
1288 value, gain_type, config);
1296 if (value[strlen(value) - 1] ==
'%')
1297 return (
int)(gain / (float)100);
1325 while (pthread_kill(monitor_thread, SIGURG) == 0)
1327 pthread_join(monitor_thread, NULL);
1373 ast_log(
LOG_ERROR,
"Config file %s is in an invalid format. Aborting.\n", config);
1390 if (!strcasecmp(v->
name,
"device")) {
1391 tmp =
mkif(v->
value, mode, txgain, rxgain);
1403 }
else if (!strcasecmp(v->
name,
"silencesupression")) {
1405 }
else if (!strcasecmp(v->
name,
"language")) {
1407 }
else if (!strcasecmp(v->
name,
"callerid")) {
1409 }
else if (!strcasecmp(v->
name,
"mode")) {
1410 if (!strncasecmp(v->
value,
"di", 2))
1412 else if (!strncasecmp(v->
value,
"sig", 3))
1414 else if (!strncasecmp(v->
value,
"im", 2))
1416 else if (!strncasecmp(v->
value,
"fxs", 3)) {
1418 prefformat = 0x01ff0000;
1420 else if (!strncasecmp(v->
value,
"fx", 2))
1424 }
else if (!strcasecmp(v->
name,
"context")) {
1426 }
else if (!strcasecmp(v->
name,
"format")) {
1427 if (!strcasecmp(v->
value,
"g729")) {
1429 }
else if (!strcasecmp(v->
value,
"g723.1")) {
1431 }
else if (!strcasecmp(v->
value,
"slinear")) {
1435 }
else if (!strcasecmp(v->
value,
"ulaw")) {
1439 }
else if (!strcasecmp(v->
name,
"echocancel")) {
1440 if (!strcasecmp(v->
value,
"off")) {
1441 echocancel = AEC_OFF;
1442 }
else if (!strcasecmp(v->
value,
"low")) {
1443 echocancel = AEC_LOW;
1444 }
else if (!strcasecmp(v->
value,
"medium")) {
1445 echocancel = AEC_MED;
1446 }
else if (!strcasecmp(v->
value,
"high")) {
1447 echocancel = AEC_HIGH;
1450 }
else if (!strcasecmp(v->
name,
"txgain")) {
1452 }
else if (!strcasecmp(v->
name,
"rxgain")) {
static char cid_num[AST_MAX_EXTENSION]
union ast_frame_subclass subclass
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
static int parse_gain_value(const char *gain_type, const char *value)
Main Channel structure associated with a channel.
static void phone_mini_packet(struct phone_pvt *i)
char * str
Subscriber phone number (Malloced)
#define AST_MODULE_INFO_STANDARD(keystr, desc)
struct ast_party_connected_line connected
Channel Connected Line ID information.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_frame * phone_read(struct ast_channel *ast)
void ast_module_unref(struct ast_module *)
static const char config[]
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame with payload.
static int phone_digit_begin(struct ast_channel *ast, char digit)
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
static pthread_t monitor_thread
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
static void * do_monitor(void *data)
struct ast_party_id id
Connected party ID.
static int phone_setup(struct ast_channel *ast)
static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
struct ast_party_name name
Subscriber name.
static ast_mutex_t iflock
#define AST_FORMAT_G723_1
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
#define ast_frame_byteswap_le(fr)
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
void ast_verbose(const char *fmt,...)
static struct ast_channel * phone_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Structure for variables, used for configurations and for channel variables.
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
static int load_module(void)
static int phone_call(struct ast_channel *ast, char *dest, int timeout)
Configuration File Parser.
char * str
Subscriber name (Malloced)
static int restart_monitor(void)
static unsigned char DialTone[]
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
static char language[MAX_LANGUAGE]
static char cid_name[AST_MAX_EXTENSION]
#define ast_mutex_lock(a)
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
static const char tdesc[]
static struct ast_channel_tech phone_tech
const ast_string_field linkedid
static ast_mutex_t monlock
static struct ast_channel_tech * cur_tech
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
#define ast_verb(level,...)
void ast_config_destroy(struct ast_config *config)
Destroys a config.
struct ast_channel * ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const char *linkedid, const int amaflag, const char *name_fmt,...)
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
String fields in structures.
#define ast_pthread_create_background(a, b, c, d)
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_channel * owner
General Asterisk PBX channel definitions.
static struct ast_channel_tech phone_tech_fxs
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
#define ast_config_load(filename, flags)
Load a config file.
static struct ast_frame * phone_exception(struct ast_channel *ast)
#define AST_PTHREADT_NULL
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_poll(a, b, c)
#define AST_MAX_EXTENSION
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
static int __unload_module(void)
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Core PBX routines and definitions.
char language[MAX_LANGUAGE]
static int phone_answer(struct ast_channel *ast)
char * ast_getformatname(format_t format)
Get the name of a format.
char ext[AST_MAX_EXTENSION]
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
char context[AST_MAX_EXTENSION]
static unsigned int monitor
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_channel_state _state
const ast_string_field name
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
char cid_num[AST_MAX_EXTENSION]
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
#define IXJ_PHONE_RING_START(x)
#define AST_FORMAT_AUDIO_MASK
static struct phone_pvt * mkif(const char *iface, int mode, int txgain, int rxgain)
if(yyss+yystacksize-1<=yyssp)
#define DEFAULT_CALLER_ID
Structure used to handle boolean flags.
#define ast_clear_flag(p, flag)
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
#define CHECK_BLOCKING(c)
static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
static struct phone_pvt * iflist
#define AST_FORMAT_SLINEAR
static int unload_module(void)
char obuf[PHONE_MAX_BUF *2]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
char offset[AST_FRIENDLY_OFFSET]
#define ast_realloc(a, b)
static char context[AST_MAX_EXTENSION]
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
#define AST_PTHREADT_STOP
static struct ast_channel * phone_new(struct phone_pvt *i, int state, char *cntx, const char *linkedid)
char * ast_getformatname_multiple(char *buf, size_t size, format_t format)
Get the names of a set of formats.
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
static int phone_send_text(struct ast_channel *ast, const char *text)
static int silencesupression
enum ast_frame_type frametype
struct ast_variable * next
static int phone_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
char cid_name[AST_MAX_EXTENSION]
unsigned char valid
TRUE if the name information is valid/present.
#define CONFIG_STATUS_FILEINVALID
static int phone_fixup(struct ast_channel *old, struct ast_channel *new)
void ast_swapcopy_samples(void *dst, const void *src, int samples)
#define ASTERISK_GPL_KEY
The text the key() function should return.
static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Asterisk module definitions.
static snd_pcm_format_t format
union ast_frame::@172 data
static int phone_hangup(struct ast_channel *ast)
unsigned char valid
TRUE if the number information is valid/present.
#define AST_MUTEX_DEFINE_STATIC(mutex)
static void phone_check_exception(struct phone_pvt *i)
static format_t prefformat
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
Same as poll(2), except the time is specified in microseconds and the tv argument is modified to indi...
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
#define ast_mutex_unlock(a)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
struct ast_module * ast_module_ref(struct ast_module *)
struct ast_party_number number
Subscriber phone number.