00001 #define NEW_ASTERISK
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #include "asterisk.h"
00060
00061 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00062
00063 #include <stdio.h>
00064 #include <ctype.h>
00065 #include <math.h>
00066 #include <string.h>
00067 #include <unistd.h>
00068 #ifdef HAVE_SYS_IO_H
00069 #include <sys/io.h>
00070 #endif
00071 #include <sys/ioctl.h>
00072 #include <fcntl.h>
00073 #include <sys/time.h>
00074 #include <stdlib.h>
00075 #include <errno.h>
00076 #include <usb.h>
00077 #include <alsa/asoundlib.h>
00078
00079
00080 #ifdef RADIO_XPMRX
00081 #define HAVE_XPMRX 1
00082 #endif
00083
00084 #define CHAN_USBRADIO 1
00085 #define DEBUG_USBRADIO 0
00086 #define DEBUG_CAPTURES 1
00087 #define DEBUG_CAP_RX_OUT 0
00088 #define DEBUG_CAP_TX_OUT 0
00089 #define DEBUG_FILETEST 0
00090
00091 #define RX_CAP_RAW_FILE "/tmp/rx_cap_in.pcm"
00092 #define RX_CAP_TRACE_FILE "/tmp/rx_trace.pcm"
00093 #define RX_CAP_OUT_FILE "/tmp/rx_cap_out.pcm"
00094
00095 #define TX_CAP_RAW_FILE "/tmp/tx_cap_in.pcm"
00096 #define TX_CAP_TRACE_FILE "/tmp/tx_trace.pcm"
00097 #define TX_CAP_OUT_FILE "/tmp/tx_cap_out.pcm"
00098
00099 #define MIXER_PARAM_MIC_PLAYBACK_SW "Mic Playback Switch"
00100 #define MIXER_PARAM_MIC_PLAYBACK_VOL "Mic Playback Volume"
00101 #define MIXER_PARAM_MIC_CAPTURE_SW "Mic Capture Switch"
00102 #define MIXER_PARAM_MIC_CAPTURE_VOL "Mic Capture Volume"
00103 #define MIXER_PARAM_MIC_BOOST "Auto Gain Control"
00104 #define MIXER_PARAM_SPKR_PLAYBACK_SW "Speaker Playback Switch"
00105 #define MIXER_PARAM_SPKR_PLAYBACK_VOL "Speaker Playback Volume"
00106
00107 #define DELIMCHR ','
00108 #define QUOTECHR 34
00109
00110 #define READERR_THRESHOLD 50
00111
00112 #include "./xpmr/xpmr.h"
00113 #ifdef HAVE_XPMRX
00114 #include "./xpmrx/xpmrx.h"
00115 #include "./xpmrx/bitweight.h"
00116 #endif
00117
00118 #if 0
00119 #define traceusb1(a) {printf a;}
00120 #else
00121 #define traceusb1(a)
00122 #endif
00123
00124 #if 0
00125 #define traceusb2(a) {printf a;}
00126 #else
00127 #define traceusb2(a)
00128 #endif
00129
00130 #ifdef __linux
00131 #include <linux/soundcard.h>
00132 #elif defined(__FreeBSD__)
00133 #include <sys/soundcard.h>
00134 #else
00135 #include <soundcard.h>
00136 #endif
00137
00138 #include "asterisk/lock.h"
00139 #include "asterisk/frame.h"
00140 #include "asterisk/logger.h"
00141 #include "asterisk/callerid.h"
00142 #include "asterisk/channel.h"
00143 #include "asterisk/module.h"
00144 #include "asterisk/options.h"
00145 #include "asterisk/pbx.h"
00146 #include "asterisk/config.h"
00147 #include "asterisk/cli.h"
00148 #include "asterisk/utils.h"
00149 #include "asterisk/causes.h"
00150 #include "asterisk/endian.h"
00151 #include "asterisk/stringfields.h"
00152 #include "asterisk/abstract_jb.h"
00153 #include "asterisk/musiconhold.h"
00154 #include "asterisk/dsp.h"
00155
00156 #ifndef NEW_ASTERISK
00157
00158
00159 #include "busy.h"
00160 #include "ringtone.h"
00161 #include "ring10.h"
00162 #include "answer.h"
00163
00164 #endif
00165
00166 #define C108_VENDOR_ID 0x0d8c
00167 #define C108_PRODUCT_ID 0x000c
00168 #define C108_HID_INTERFACE 3
00169
00170 #define HID_REPORT_GET 0x01
00171 #define HID_REPORT_SET 0x09
00172
00173 #define HID_RT_INPUT 0x01
00174 #define HID_RT_OUTPUT 0x02
00175
00176 #define EEPROM_START_ADDR 6
00177 #define EEPROM_END_ADDR 63
00178 #define EEPROM_PHYSICAL_LEN 64
00179 #define EEPROM_TEST_ADDR EEPROM_END_ADDR
00180 #define EEPROM_MAGIC_ADDR 6
00181 #define EEPROM_MAGIC 34329
00182 #define EEPROM_CS_ADDR 62
00183 #define EEPROM_RXMIXERSET 8
00184 #define EEPROM_TXMIXASET 9
00185 #define EEPROM_TXMIXBSET 10
00186 #define EEPROM_RXVOICEADJ 11
00187 #define EEPROM_RXCTCSSADJ 13
00188 #define EEPROM_TXCTCSSADJ 15
00189 #define EEPROM_RXSQUELCHADJ 16
00190
00191
00192
00193 static struct ast_jb_conf default_jbconf =
00194 {
00195 .flags = 0,
00196 .max_size = 200,
00197 .resync_threshold = 1000,
00198 .impl = "fixed",
00199 .target_extra = 40,
00200 };
00201 static struct ast_jb_conf global_jbconf;
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 #define M_START(var, val) \
00295 char *__s = var; char *__val = val;
00296 #define M_END(x) x;
00297 #define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
00298 #define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
00299 #define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
00300 #define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 #define FRAME_SIZE 160
00333 #define QUEUE_SIZE 2
00334
00335 #if defined(__FreeBSD__)
00336 #define FRAGS 0x8
00337 #else
00338 #define FRAGS ( ( (6 * 5) << 16 ) | 0xc )
00339 #endif
00340
00341
00342
00343
00344
00345 #define TEXT_SIZE 256
00346
00347 #if 0
00348 #define TRYOPEN 1
00349 #endif
00350 #define O_CLOSE 0x444
00351
00352 #if defined( __OpenBSD__ ) || defined( __NetBSD__ )
00353 #define DEV_DSP "/dev/audio"
00354 #else
00355 #define DEV_DSP "/dev/dsp"
00356 #endif
00357
00358 static const char *config = "usbradio.conf";
00359 #define config1 "usbradio_tune_%s.conf"
00360
00361 static FILE *frxcapraw = NULL, *frxcaptrace = NULL, *frxoutraw = NULL;
00362 static FILE *ftxcapraw = NULL, *ftxcaptrace = NULL, *ftxoutraw = NULL;
00363
00364 static char *usb_device_list = NULL;
00365 static int usb_device_list_size = 0;
00366
00367 static int usbradio_debug;
00368 #if 0 //maw asdf sph
00369 static int usbradio_debug_level = 0;
00370 #endif
00371
00372 enum {RX_AUDIO_NONE,RX_AUDIO_SPEAKER,RX_AUDIO_FLAT};
00373 enum {CD_IGNORE,CD_XPMR_NOISE,CD_XPMR_VOX,CD_HID,CD_HID_INVERT};
00374 enum {SD_IGNORE,SD_HID,SD_HID_INVERT,SD_XPMR};
00375 enum {RX_KEY_CARRIER,RX_KEY_CARRIER_CODE};
00376 enum {TX_OUT_OFF,TX_OUT_VOICE,TX_OUT_LSD,TX_OUT_COMPOSITE,TX_OUT_AUX};
00377 enum {TOC_NONE,TOC_PHASE,TOC_NOTONE};
00378
00379
00380
00381
00382
00383
00384
00385
00386 struct sound {
00387 int ind;
00388 char *desc;
00389 short *data;
00390 int datalen;
00391 int samplen;
00392 int silencelen;
00393 int repeat;
00394 };
00395
00396 #ifndef NEW_ASTERISK
00397
00398 static struct sound sounds[] = {
00399 { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
00400 { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
00401 { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
00402 { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
00403 { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
00404 { -1, NULL, 0, 0, 0, 0 },
00405 };
00406
00407 #endif
00408
00409
00410
00411
00412
00413
00414
00415
00416 struct chan_usbradio_pvt {
00417 struct chan_usbradio_pvt *next;
00418
00419 char *name;
00420 #ifndef NEW_ASTERISK
00421
00422
00423
00424
00425
00426
00427
00428 int sndcmd[2];
00429 int cursound;
00430 int sampsent;
00431 int nosound;
00432 #endif
00433
00434 int pttkick[2];
00435 int total_blocks;
00436 int sounddev;
00437 enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
00438 i16 cdMethod;
00439 int autoanswer;
00440 int autohangup;
00441 int hookstate;
00442 unsigned int queuesize;
00443 unsigned int frags;
00444
00445 int warned;
00446 #define WARN_used_blocks 1
00447 #define WARN_speed 2
00448 #define WARN_frag 4
00449 int w_errors;
00450 struct timeval lastopen;
00451
00452 int overridecontext;
00453 int mute;
00454
00455
00456
00457
00458 #define BOOST_SCALE (1<<9)
00459 #define BOOST_MAX 40
00460 int boost;
00461 char devicenum;
00462 char devstr[128];
00463 int spkrmax;
00464 int micmax;
00465
00466 #ifndef NEW_ASTERISK
00467 pthread_t sthread;
00468 #endif
00469 pthread_t hidthread;
00470
00471 int stophid;
00472 FILE *hkickhid;
00473
00474 struct ast_channel *owner;
00475 char ext[AST_MAX_EXTENSION];
00476 char ctx[AST_MAX_CONTEXT];
00477 char language[MAX_LANGUAGE];
00478 char cid_name[256];
00479 char cid_num[256];
00480 char mohinterpret[MAX_MUSICCLASS];
00481
00482
00483 char usbradio_write_buf[FRAME_SIZE * 2 * 2 * 6];
00484 char usbradio_write_buf_1[FRAME_SIZE * 2 * 2* 6];
00485
00486 int usbradio_write_dst;
00487
00488
00489
00490 char usbradio_read_buf[FRAME_SIZE * (2 * 12) + AST_FRIENDLY_OFFSET];
00491 char usbradio_read_buf_8k[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
00492 int readpos;
00493 struct ast_frame read_f;
00494
00495 char debuglevel;
00496 char radioduplex;
00497 char wanteeprom;
00498
00499 int tracetype;
00500 int tracelevel;
00501 char area;
00502 char rptnum;
00503 int idleinterval;
00504 int turnoffs;
00505 int txsettletime;
00506 char ukey[48];
00507
00508 char lastrx;
00509 char rxhidsq;
00510 char rxcarrierdetect;
00511 char rxctcssdecode;
00512
00513 int rxdcsdecode;
00514 int rxlsddecode;
00515
00516 char rxkeytype;
00517 char rxkeyed;
00518
00519 char lasttx;
00520 char txkeyed;
00521 char txchankey;
00522 char txtestkey;
00523
00524 time_t lasthidtime;
00525 struct ast_dsp *dsp;
00526
00527 t_pmr_chan *pmrChan;
00528
00529 char rxcpusaver;
00530 char txcpusaver;
00531
00532 char rxdemod;
00533 float rxgain;
00534 char rxcdtype;
00535 char rxsdtype;
00536 int rxsquelchadj;
00537 int rxsqvoxadj;
00538 char txtoctype;
00539
00540 char txprelim;
00541 float txctcssgain;
00542 char txmixa;
00543 char txmixb;
00544
00545 char invertptt;
00546
00547 char rxctcssrelax;
00548 float rxctcssgain;
00549
00550 char txctcssdefault[16];
00551 char rxctcssfreqs[512];
00552 char txctcssfreqs[512];
00553
00554 char txctcssfreq[32];
00555 char rxctcssfreq[32];
00556
00557 char numrxctcssfreqs;
00558 char numtxctcssfreqs;
00559
00560 char *rxctcss[CTCSS_NUM_CODES];
00561 char *txctcss[CTCSS_NUM_CODES];
00562
00563 int txfreq;
00564 int rxfreq;
00565
00566
00567 char set_txctcssdefault[16];
00568 char set_txctcssfreq[16];
00569 char set_rxctcssfreq[16];
00570
00571 char set_numrxctcssfreqs;
00572 char set_numtxctcssfreqs;
00573
00574 char set_rxctcssfreqs[16];
00575 char set_txctcssfreqs[16];
00576
00577 char *set_rxctcss;
00578 char *set_txctcss;
00579
00580 int set_txfreq;
00581 int set_rxfreq;
00582
00583
00584 int rxmixerset;
00585 int rxboostset;
00586 float rxvoiceadj;
00587 float rxctcssadj;
00588 int txmixaset;
00589 int txmixbset;
00590 int txctcssadj;
00591
00592 int hdwtype;
00593 int hid_gpio_ctl;
00594 int hid_gpio_ctl_loc;
00595 int hid_io_cor;
00596 int hid_io_cor_loc;
00597 int hid_io_ctcss;
00598 int hid_io_ctcss_loc;
00599 int hid_io_ptt;
00600 int hid_gpio_loc;
00601
00602 struct {
00603 unsigned rxcapraw:1;
00604 unsigned txcapraw:1;
00605 unsigned txcap2:1;
00606 unsigned rxcap2:1;
00607 unsigned rxplmon:1;
00608 unsigned remoted:1;
00609 unsigned txpolarity:1;
00610 unsigned rxpolarity:1;
00611 unsigned dcstxpolarity:1;
00612 unsigned dcsrxpolarity:1;
00613 unsigned lsdtxpolarity:1;
00614 unsigned lsdrxpolarity:1;
00615 unsigned loopback:1;
00616 unsigned radioactive:1;
00617 }b;
00618 unsigned short eeprom[EEPROM_PHYSICAL_LEN];
00619 char eepromctl;
00620 ast_mutex_t eepromlock;
00621
00622 struct usb_dev_handle *usb_handle;
00623 int readerrs;
00624 };
00625
00626
00627 static struct chan_usbradio_pvt usbradio_default = {
00628 #ifndef NEW_ASTERISK
00629 .cursound = -1,
00630 #endif
00631 .sounddev = -1,
00632 .duplex = M_UNSET,
00633 .autoanswer = 1,
00634 .autohangup = 1,
00635 .queuesize = QUEUE_SIZE,
00636 .frags = FRAGS,
00637 .ext = "s",
00638 .ctx = "default",
00639 .readpos = AST_FRIENDLY_OFFSET,
00640 .lastopen = { 0, 0 },
00641 .boost = BOOST_SCALE,
00642 .wanteeprom = 1,
00643 .area = 0,
00644 .rptnum = 0,
00645 };
00646
00647
00648
00649 static void store_txtoctype(struct chan_usbradio_pvt *o, const char *s);
00650 static int hidhdwconfig(struct chan_usbradio_pvt *o);
00651 static int set_txctcss_level(struct chan_usbradio_pvt *o);
00652 static void pmrdump(struct chan_usbradio_pvt *o);
00653 static void mult_set(struct chan_usbradio_pvt *o);
00654 static int mult_calc(int value);
00655 static void mixer_write(struct chan_usbradio_pvt *o);
00656 static void tune_rxinput(int fd, struct chan_usbradio_pvt *o);
00657 static void tune_rxvoice(int fd, struct chan_usbradio_pvt *o);
00658 static void tune_rxctcss(int fd, struct chan_usbradio_pvt *o);
00659 static void tune_txoutput(struct chan_usbradio_pvt *o, int value, int fd);
00660 static void tune_write(struct chan_usbradio_pvt *o);
00661
00662 static char *usbradio_active;
00663
00664 static int setformat(struct chan_usbradio_pvt *o, int mode);
00665
00666 static struct ast_channel *usbradio_request(const char *type, format_t format,
00667 const struct ast_channel *requestor,
00668 void *data, int *cause);
00669 static int usbradio_digit_begin(struct ast_channel *c, char digit);
00670 static int usbradio_digit_end(struct ast_channel *c, char digit, unsigned int duration);
00671 static int usbradio_text(struct ast_channel *c, const char *text);
00672 static int usbradio_hangup(struct ast_channel *c);
00673 static int usbradio_answer(struct ast_channel *c);
00674 static struct ast_frame *usbradio_read(struct ast_channel *chan);
00675 static int usbradio_call(struct ast_channel *c, char *dest, int timeout);
00676 static int usbradio_write(struct ast_channel *chan, struct ast_frame *f);
00677 static int usbradio_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00678 static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00679 static int xpmr_config(struct chan_usbradio_pvt *o);
00680
00681 #if DEBUG_FILETEST == 1
00682 static int RxTestIt(struct chan_usbradio_pvt *o);
00683 #endif
00684
00685 static char tdesc[] = "USB (CM108) Radio Channel Driver";
00686
00687 static const struct ast_channel_tech usbradio_tech = {
00688 .type = "Radio",
00689 .description = tdesc,
00690 .capabilities = AST_FORMAT_SLINEAR,
00691 .requester = usbradio_request,
00692 .send_digit_begin = usbradio_digit_begin,
00693 .send_digit_end = usbradio_digit_end,
00694 .send_text = usbradio_text,
00695 .hangup = usbradio_hangup,
00696 .answer = usbradio_answer,
00697 .read = usbradio_read,
00698 .call = usbradio_call,
00699 .write = usbradio_write,
00700 .indicate = usbradio_indicate,
00701 .fixup = usbradio_fixup,
00702 };
00703
00704
00705
00706
00707
00708
00709
00710 static int amixer_max(int devnum,char *param)
00711 {
00712 int rv,type;
00713 char str[100];
00714 snd_hctl_t *hctl;
00715 snd_ctl_elem_id_t *id;
00716 snd_hctl_elem_t *elem;
00717 snd_ctl_elem_info_t *info;
00718
00719 sprintf(str,"hw:%d",devnum);
00720 if (snd_hctl_open(&hctl, str, 0)) return(-1);
00721 snd_hctl_load(hctl);
00722 snd_ctl_elem_id_alloca(&id);
00723 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
00724 snd_ctl_elem_id_set_name(id, param);
00725 elem = snd_hctl_find_elem(hctl, id);
00726 if (!elem)
00727 {
00728 snd_hctl_close(hctl);
00729 return(-1);
00730 }
00731 snd_ctl_elem_info_alloca(&info);
00732 snd_hctl_elem_info(elem,info);
00733 type = snd_ctl_elem_info_get_type(info);
00734 rv = 0;
00735 switch(type)
00736 {
00737 case SND_CTL_ELEM_TYPE_INTEGER:
00738 rv = snd_ctl_elem_info_get_max(info);
00739 break;
00740 case SND_CTL_ELEM_TYPE_BOOLEAN:
00741 rv = 1;
00742 break;
00743 }
00744 snd_hctl_close(hctl);
00745 return(rv);
00746 }
00747
00748
00749
00750
00751
00752
00753
00754 static int setamixer(int devnum,char *param, int v1, int v2)
00755 {
00756 int type;
00757 char str[100];
00758 snd_hctl_t *hctl;
00759 snd_ctl_elem_id_t *id;
00760 snd_ctl_elem_value_t *control;
00761 snd_hctl_elem_t *elem;
00762 snd_ctl_elem_info_t *info;
00763
00764 sprintf(str,"hw:%d",devnum);
00765 if (snd_hctl_open(&hctl, str, 0)) return(-1);
00766 snd_hctl_load(hctl);
00767 snd_ctl_elem_id_alloca(&id);
00768 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
00769 snd_ctl_elem_id_set_name(id, param);
00770 elem = snd_hctl_find_elem(hctl, id);
00771 if (!elem)
00772 {
00773 snd_hctl_close(hctl);
00774 return(-1);
00775 }
00776 snd_ctl_elem_info_alloca(&info);
00777 snd_hctl_elem_info(elem,info);
00778 type = snd_ctl_elem_info_get_type(info);
00779 snd_ctl_elem_value_alloca(&control);
00780 snd_ctl_elem_value_set_id(control, id);
00781 switch(type)
00782 {
00783 case SND_CTL_ELEM_TYPE_INTEGER:
00784 snd_ctl_elem_value_set_integer(control, 0, v1);
00785 if (v2 > 0) snd_ctl_elem_value_set_integer(control, 1, v2);
00786 break;
00787 case SND_CTL_ELEM_TYPE_BOOLEAN:
00788 snd_ctl_elem_value_set_integer(control, 0, (v1 != 0));
00789 break;
00790 }
00791 if (snd_hctl_elem_write(elem, control))
00792 {
00793 snd_hctl_close(hctl);
00794 return(-1);
00795 }
00796 snd_hctl_close(hctl);
00797 return(0);
00798 }
00799
00800 static void hid_set_outputs(struct usb_dev_handle *handle,
00801 unsigned char *outputs)
00802 {
00803 usleep(1500);
00804 usb_control_msg(handle,
00805 USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE,
00806 HID_REPORT_SET,
00807 0 + (HID_RT_OUTPUT << 8),
00808 C108_HID_INTERFACE,
00809 (char*)outputs, 4, 5000);
00810 }
00811
00812 static void hid_get_inputs(struct usb_dev_handle *handle,
00813 unsigned char *inputs)
00814 {
00815 usleep(1500);
00816 usb_control_msg(handle,
00817 USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE,
00818 HID_REPORT_GET,
00819 0 + (HID_RT_INPUT << 8),
00820 C108_HID_INTERFACE,
00821 (char*)inputs, 4, 5000);
00822 }
00823
00824 static unsigned short read_eeprom(struct usb_dev_handle *handle, int addr)
00825 {
00826 unsigned char buf[4];
00827
00828 buf[0] = 0x80;
00829 buf[1] = 0;
00830 buf[2] = 0;
00831 buf[3] = 0x80 | (addr & 0x3f);
00832 hid_set_outputs(handle,buf);
00833 memset(buf,0,sizeof(buf));
00834 hid_get_inputs(handle,buf);
00835 return(buf[1] + (buf[2] << 8));
00836 }
00837
00838 static void write_eeprom(struct usb_dev_handle *handle, int addr,
00839 unsigned short data)
00840 {
00841
00842 unsigned char buf[4];
00843
00844 buf[0] = 0x80;
00845 buf[1] = data & 0xff;
00846 buf[2] = data >> 8;
00847 buf[3] = 0xc0 | (addr & 0x3f);
00848 hid_set_outputs(handle,buf);
00849 }
00850
00851 static unsigned short get_eeprom(struct usb_dev_handle *handle,
00852 unsigned short *buf)
00853 {
00854 int i;
00855 unsigned short cs;
00856
00857 cs = 0xffff;
00858 for(i = EEPROM_START_ADDR; i < EEPROM_END_ADDR; i++)
00859 {
00860 cs += buf[i] = read_eeprom(handle,i);
00861 }
00862 return(cs);
00863 }
00864
00865 static void put_eeprom(struct usb_dev_handle *handle,unsigned short *buf)
00866 {
00867 int i;
00868 unsigned short cs;
00869
00870 cs = 0xffff;
00871 buf[EEPROM_MAGIC_ADDR] = EEPROM_MAGIC;
00872 for(i = EEPROM_START_ADDR; i < EEPROM_CS_ADDR; i++)
00873 {
00874 write_eeprom(handle,i,buf[i]);
00875 cs += buf[i];
00876 }
00877 buf[EEPROM_CS_ADDR] = (65535 - cs) + 1;
00878 write_eeprom(handle,i,buf[EEPROM_CS_ADDR]);
00879 }
00880
00881 static struct usb_device *hid_device_init(char *desired_device)
00882 {
00883 struct usb_bus *usb_bus;
00884 struct usb_device *dev;
00885 char devstr[200],str[200],desdev[200],*cp;
00886 int i;
00887 FILE *fp;
00888
00889 usb_init();
00890 usb_find_busses();
00891 usb_find_devices();
00892 for (usb_bus = usb_busses;
00893 usb_bus;
00894 usb_bus = usb_bus->next) {
00895 for (dev = usb_bus->devices;
00896 dev;
00897 dev = dev->next) {
00898 if ((dev->descriptor.idVendor
00899 == C108_VENDOR_ID) &&
00900 (dev->descriptor.idProduct
00901 == C108_PRODUCT_ID))
00902 {
00903 sprintf(devstr,"%s/%s", usb_bus->dirname,dev->filename);
00904 for(i = 0; i < 32; i++)
00905 {
00906 sprintf(str,"/proc/asound/card%d/usbbus",i);
00907 fp = fopen(str,"r");
00908 if (!fp) continue;
00909 if ((!fgets(desdev,sizeof(desdev) - 1,fp)) || (!desdev[0]))
00910 {
00911 fclose(fp);
00912 continue;
00913 }
00914 fclose(fp);
00915 if (desdev[strlen(desdev) - 1] == '\n')
00916 desdev[strlen(desdev) -1 ] = 0;
00917 if (strcasecmp(desdev,devstr)) continue;
00918 if (i) sprintf(str,"/sys/class/sound/dsp%d/device",i);
00919 else strcpy(str,"/sys/class/sound/dsp/device");
00920 memset(desdev,0,sizeof(desdev));
00921 if (readlink(str,desdev,sizeof(desdev) - 1) == -1)
00922 {
00923 sprintf(str,"/sys/class/sound/controlC%d/device",i);
00924 memset(desdev,0,sizeof(desdev));
00925 if (readlink(str,desdev,sizeof(desdev) - 1) == -1) continue;
00926 }
00927 cp = strrchr(desdev,'/');
00928 if (cp) *cp = 0; else continue;
00929 cp = strrchr(desdev,'/');
00930 if (!cp) continue;
00931 cp++;
00932 break;
00933 }
00934 if (i >= 32) continue;
00935 if (!strcmp(cp,desired_device)) return dev;
00936 }
00937
00938 }
00939 }
00940 return NULL;
00941 }
00942
00943 static int hid_device_mklist(void)
00944 {
00945 struct usb_bus *usb_bus;
00946 struct usb_device *dev;
00947 char devstr[200],str[200],desdev[200],*cp;
00948 int i;
00949 FILE *fp;
00950
00951 usb_device_list = ast_malloc(2);
00952 if (!usb_device_list) return -1;
00953 memset(usb_device_list,0,2);
00954
00955 usb_init();
00956 usb_find_busses();
00957 usb_find_devices();
00958 for (usb_bus = usb_busses;
00959 usb_bus;
00960 usb_bus = usb_bus->next) {
00961 for (dev = usb_bus->devices;
00962 dev;
00963 dev = dev->next) {
00964 if ((dev->descriptor.idVendor
00965 == C108_VENDOR_ID) &&
00966 (dev->descriptor.idProduct
00967 == C108_PRODUCT_ID))
00968 {
00969 sprintf(devstr,"%s/%s", usb_bus->dirname,dev->filename);
00970 for(i = 0;i < 32; i++)
00971 {
00972 sprintf(str,"/proc/asound/card%d/usbbus",i);
00973 fp = fopen(str,"r");
00974 if (!fp) continue;
00975 if ((!fgets(desdev,sizeof(desdev) - 1,fp)) || (!desdev[0]))
00976 {
00977 fclose(fp);
00978 continue;
00979 }
00980 fclose(fp);
00981 if (desdev[strlen(desdev) - 1] == '\n')
00982 desdev[strlen(desdev) -1 ] = 0;
00983 if (strcasecmp(desdev,devstr)) continue;
00984 if (i) sprintf(str,"/sys/class/sound/dsp%d/device",i);
00985 else strcpy(str,"/sys/class/sound/dsp/device");
00986 memset(desdev,0,sizeof(desdev));
00987 if (readlink(str,desdev,sizeof(desdev) - 1) == -1)
00988 {
00989 sprintf(str,"/sys/class/sound/controlC%d/device",i);
00990 memset(desdev,0,sizeof(desdev));
00991 if (readlink(str,desdev,sizeof(desdev) - 1) == -1) continue;
00992 }
00993 cp = strrchr(desdev,'/');
00994 if (cp) *cp = 0; else continue;
00995 cp = strrchr(desdev,'/');
00996 if (!cp) continue;
00997 cp++;
00998 break;
00999 }
01000 if (i >= 32) return -1;
01001 usb_device_list = ast_realloc(usb_device_list,
01002 usb_device_list_size + 2 +
01003 strlen(cp));
01004 if (!usb_device_list) return -1;
01005 usb_device_list_size += strlen(cp) + 2;
01006 i = 0;
01007 while(usb_device_list[i])
01008 {
01009 i += strlen(usb_device_list + i) + 1;
01010 }
01011 strcat(usb_device_list + i,cp);
01012 usb_device_list[strlen(cp) + i + 1] = 0;
01013 }
01014
01015 }
01016 }
01017 return 0;
01018 }
01019
01020
01021 static int usb_get_usbdev(char *devstr)
01022 {
01023 int i;
01024 char str[200],desdev[200],*cp;
01025
01026 for(i = 0;i < 32; i++)
01027 {
01028 if (i) sprintf(str,"/sys/class/sound/dsp%d/device",i);
01029 else strcpy(str,"/sys/class/sound/dsp/device");
01030 memset(desdev,0,sizeof(desdev));
01031 if (readlink(str,desdev,sizeof(desdev) - 1) == -1)
01032 {
01033 sprintf(str,"/sys/class/sound/controlC%d/device",i);
01034 memset(desdev,0,sizeof(desdev));
01035 if (readlink(str,desdev,sizeof(desdev) - 1) == -1) continue;
01036 }
01037 cp = strrchr(desdev,'/');
01038 if (cp) *cp = 0; else continue;
01039 cp = strrchr(desdev,'/');
01040 if (!cp) continue;
01041 cp++;
01042 if (!strcasecmp(cp,devstr)) break;
01043 }
01044 if (i >= 32) return -1;
01045 return i;
01046
01047 }
01048
01049 static int usb_list_check(char *devstr)
01050 {
01051
01052 char *s = usb_device_list;
01053
01054 if (!s) return(0);
01055 while(*s)
01056 {
01057 if (!strcasecmp(s,devstr)) return(1);
01058 s += strlen(s) + 1;
01059 }
01060 return(0);
01061 }
01062
01063
01064 static int hidhdwconfig(struct chan_usbradio_pvt *o)
01065 {
01066 if(o->hdwtype==1)
01067 {
01068 o->hid_gpio_ctl = 0x08;
01069 o->hid_gpio_ctl_loc = 2;
01070 o->hid_io_cor = 4;
01071 o->hid_io_cor_loc = 1;
01072 o->hid_io_ctcss = 2;
01073 o->hid_io_ctcss_loc = 1;
01074 o->hid_io_ptt = 8;
01075 o->hid_gpio_loc = 1;
01076 }
01077 else if(o->hdwtype==0)
01078 {
01079 o->hid_gpio_ctl = 0x0c;
01080 o->hid_gpio_ctl_loc = 2;
01081 o->hid_io_cor = 2;
01082 o->hid_io_cor_loc = 0;
01083 o->hid_io_ctcss = 2;
01084 o->hid_io_ctcss_loc = 1;
01085 o->hid_io_ptt = 4;
01086 o->hid_gpio_loc = 1;
01087 }
01088 else if(o->hdwtype==3)
01089 {
01090 o->hid_gpio_ctl = 0x0c;
01091 o->hid_gpio_ctl_loc = 2;
01092 o->hid_io_cor = 2;
01093 o->hid_io_cor_loc = 0;
01094 o->hid_io_ctcss = 2;
01095 o->hid_io_ctcss_loc = 1;
01096 o->hid_io_ptt = 4;
01097 o->hid_gpio_loc = 1;
01098 }
01099
01100 return 0;
01101 }
01102
01103
01104 static void kickptt(struct chan_usbradio_pvt *o)
01105 {
01106 char c = 0;
01107
01108 if (!o) return;
01109 if (!o->pttkick) return;
01110 if (write(o->pttkick[1],&c,1) < 0) {
01111 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
01112 }
01113 }
01114
01115
01116 static void *hidthread(void *arg)
01117 {
01118 unsigned char buf[4],bufsave[4],keyed;
01119 char lastrx, txtmp;
01120 int res;
01121 struct usb_device *usb_dev;
01122 struct usb_dev_handle *usb_handle;
01123 struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
01124 struct pollfd pfd = { .events = POLLIN };
01125
01126 usb_dev = hid_device_init(o->devstr);
01127 if (usb_dev == NULL) {
01128 ast_log(LOG_ERROR,"USB HID device not found\n");
01129 pthread_exit(NULL);
01130 }
01131 usb_handle = usb_open(usb_dev);
01132 if (usb_handle == NULL) {
01133 ast_log(LOG_ERROR,"Not able to open USB device\n");
01134 pthread_exit(NULL);
01135 }
01136 if (usb_claim_interface(usb_handle,C108_HID_INTERFACE) < 0)
01137 {
01138 if (usb_detach_kernel_driver_np(usb_handle,C108_HID_INTERFACE) < 0) {
01139 ast_log(LOG_ERROR,"Not able to detach the USB device\n");
01140 pthread_exit(NULL);
01141 }
01142 if (usb_claim_interface(usb_handle,C108_HID_INTERFACE) < 0) {
01143 ast_log(LOG_ERROR,"Not able to claim the USB device\n");
01144 pthread_exit(NULL);
01145 }
01146 }
01147 memset(buf,0,sizeof(buf));
01148 buf[2] = o->hid_gpio_ctl;
01149 buf[1] = 0;
01150 hid_set_outputs(usb_handle,buf);
01151 memcpy(bufsave,buf,sizeof(buf));
01152 if (pipe(o->pttkick) == -1)
01153 {
01154 ast_log(LOG_ERROR,"Not able to create pipe\n");
01155 pthread_exit(NULL);
01156 }
01157 traceusb1(("hidthread: Starting normally on %s!!\n",o->name));
01158 lastrx = 0;
01159
01160 while (!o->stophid) {
01161 pfd.fd = o->pttkick[0];
01162 pfd.revents = 0;
01163
01164 res = ast_poll(&pfd, 1, 50);
01165 if (res < 0) {
01166 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
01167 usleep(10000);
01168 continue;
01169 }
01170 if (pfd.revents & POLLIN) {
01171 char c;
01172
01173 if (read(o->pttkick[0], &c, 1) < 0) {
01174 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
01175 }
01176 }
01177 if (o->wanteeprom) {
01178 ast_mutex_lock(&o->eepromlock);
01179 if (o->eepromctl == 1) {
01180
01181 if (!get_eeprom(usb_handle, o->eeprom)) {
01182 if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) {
01183 ast_log(LOG_NOTICE, "UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n", o->name);
01184 } else {
01185 o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET];
01186 o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
01187 o->txmixbset = o->eeprom[EEPROM_TXMIXBSET];
01188 memcpy(&o->rxvoiceadj, &o->eeprom[EEPROM_RXVOICEADJ], sizeof(float));
01189 memcpy(&o->rxctcssadj, &o->eeprom[EEPROM_RXCTCSSADJ], sizeof(float));
01190 o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ];
01191 o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ];
01192 ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name);
01193 }
01194 } else {
01195 ast_log(LOG_NOTICE, "USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n", o->name);
01196 }
01197 hid_set_outputs(usb_handle,bufsave);
01198 }
01199 if (o->eepromctl == 2) {
01200 put_eeprom(usb_handle,o->eeprom);
01201 hid_set_outputs(usb_handle,bufsave);
01202 ast_log(LOG_NOTICE, "USB Parameters written to EEPROM on %s\n", o->name);
01203 }
01204 o->eepromctl = 0;
01205 ast_mutex_unlock(&o->eepromlock);
01206 }
01207 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
01208 hid_get_inputs(usb_handle,buf);
01209 keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor);
01210 if (keyed != o->rxhidsq) {
01211 if (o->debuglevel) {
01212 printf("chan_usbradio() hidthread: update rxhidsq = %d\n", keyed);
01213 }
01214 o->rxhidsq=keyed;
01215 }
01216
01217
01218 txtmp = o->pmrChan->txPttOut;
01219
01220 if (o->lasttx != txtmp) {
01221 o->pmrChan->txPttHid = o->lasttx = txtmp;
01222 if (o->debuglevel) {
01223 ast_debug(0, "hidthread: tx set to %d\n", txtmp);
01224 }
01225 buf[o->hid_gpio_loc] = 0;
01226 if (!o->invertptt) {
01227 if (txtmp) {
01228 buf[o->hid_gpio_loc] = o->hid_io_ptt;
01229 }
01230 } else {
01231 if (!txtmp) {
01232 buf[o->hid_gpio_loc] = o->hid_io_ptt;
01233 }
01234 }
01235 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
01236 memcpy(bufsave, buf, sizeof(buf));
01237 hid_set_outputs(usb_handle, buf);
01238 }
01239 time(&o->lasthidtime);
01240 }
01241 buf[o->hid_gpio_loc] = 0;
01242 if (o->invertptt) {
01243 buf[o->hid_gpio_loc] = o->hid_io_ptt;
01244 }
01245 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
01246 hid_set_outputs(usb_handle, buf);
01247 pthread_exit(0);
01248 }
01249
01250
01251
01252
01253 static struct chan_usbradio_pvt *find_desc(char *dev)
01254 {
01255 struct chan_usbradio_pvt *o = NULL;
01256
01257 if (!dev)
01258 ast_log(LOG_WARNING, "null dev\n");
01259
01260 for (o = usbradio_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
01261 if (!o)
01262 {
01263 ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
01264 }
01265
01266 return o;
01267 }
01268
01269 static struct chan_usbradio_pvt *find_desc_usb(char *devstr)
01270 {
01271 struct chan_usbradio_pvt *o = NULL;
01272
01273 if (!devstr)
01274 ast_log(LOG_WARNING, "null dev\n");
01275
01276 for (o = usbradio_default.next; o && devstr && strcmp(o->devstr, devstr) != 0; o = o->next);
01277
01278 return o;
01279 }
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290 #if 0
01291 static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
01292 {
01293 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
01294
01295 if (ext == NULL || ctx == NULL)
01296 return NULL;
01297
01298 *ext = *ctx = NULL;
01299
01300 if (src && *src != '\0')
01301 *ext = ast_strdup(src);
01302
01303 if (*ext == NULL)
01304 return NULL;
01305
01306 if (!o->overridecontext) {
01307
01308 *ctx = strrchr(*ext, '@');
01309 if (*ctx)
01310 *(*ctx)++ = '\0';
01311 }
01312
01313 return *ext;
01314 }
01315 #endif
01316
01317
01318
01319
01320 static int used_blocks(struct chan_usbradio_pvt *o)
01321 {
01322 struct audio_buf_info info;
01323
01324 if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
01325 if (!(o->warned & WARN_used_blocks)) {
01326 ast_log(LOG_WARNING, "Error reading output space\n");
01327 o->warned |= WARN_used_blocks;
01328 }
01329 return 1;
01330 }
01331
01332 if (o->total_blocks == 0) {
01333 if (0)
01334 ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
01335 o->total_blocks = info.fragments;
01336 }
01337
01338 return o->total_blocks - info.fragments;
01339 }
01340
01341
01342 static int soundcard_writeframe(struct chan_usbradio_pvt *o, short *data)
01343 {
01344 int res;
01345
01346 if (o->sounddev < 0)
01347 setformat(o, O_RDWR);
01348 if (o->sounddev < 0)
01349 return 0;
01350
01351
01352
01353 if(!o->pmrChan->txPttIn && !o->pmrChan->txPttOut)
01354 {
01355
01356 }
01357
01358
01359
01360
01361
01362
01363 res = used_blocks(o);
01364 if (res > o->queuesize) {
01365
01366 if (o->w_errors++ == 0 && (usbradio_debug & 0x4))
01367 ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
01368 return 0;
01369 }
01370 o->w_errors = 0;
01371
01372 return write(o->sounddev, ((void *) data), FRAME_SIZE * 2 * 12);
01373 }
01374
01375 #ifndef NEW_ASTERISK
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 static void send_sound(struct chan_usbradio_pvt *o)
01388 {
01389 short myframe[FRAME_SIZE];
01390 int ofs, l, start;
01391 int l_sampsent = o->sampsent;
01392 struct sound *s;
01393
01394 if (o->cursound < 0)
01395 return;
01396
01397 s = &sounds[o->cursound];
01398
01399 for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
01400 l = s->samplen - l_sampsent;
01401 if (l > 0) {
01402 start = l_sampsent % s->datalen;
01403 if (l > FRAME_SIZE - ofs)
01404 l = FRAME_SIZE - ofs;
01405 if (l > s->datalen - start)
01406 l = s->datalen - start;
01407 memmove(myframe + ofs, s->data + start, l * 2);
01408 if (0)
01409 ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);
01410 l_sampsent += l;
01411 } else {
01412 static const short silence[FRAME_SIZE] = { 0, };
01413
01414 l += s->silencelen;
01415 if (l > 0) {
01416 if (l > FRAME_SIZE - ofs)
01417 l = FRAME_SIZE - ofs;
01418 memmove(myframe + ofs, silence, l * 2);
01419 l_sampsent += l;
01420 } else {
01421 if (s->repeat == 0) {
01422 o->cursound = -1;
01423 o->nosound = 0;
01424 if (ofs < FRAME_SIZE)
01425 memmove(myframe + ofs, silence, (FRAME_SIZE - ofs) * 2);
01426 }
01427 l_sampsent = 0;
01428 }
01429 }
01430 }
01431 l = soundcard_writeframe(o, myframe);
01432 if (l > 0)
01433 o->sampsent = l_sampsent;
01434 }
01435
01436 static void *sound_thread(void *arg)
01437 {
01438 char ign[4096];
01439 struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
01440
01441
01442
01443
01444
01445 read(o->sounddev, ign, sizeof(ign));
01446 for (;;) {
01447 struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
01448 int res;
01449
01450 if (o->cursound > -1 && o->sounddev < 0) {
01451 setformat(o, O_RDWR);
01452 } else if (o->cursound == -1 && o->owner == NULL) {
01453 setformat(o, O_CLOSE);
01454 }
01455 if (o->sounddev > -1) {
01456 if (!o->owner) {
01457 pfd[1].events = POLLIN;
01458 }
01459 if (o->cursound > -1) {
01460 pfd[1].events |= POLLOUT;
01461 }
01462 }
01463 res = ast_poll(pfd, o->sounddev > -1 ? 2 : 1, -1);
01464 if (res < 1) {
01465 ast_log(LOG_WARNING, "poll failed: %s\n", strerror(errno));
01466 sleep(1);
01467 continue;
01468 }
01469 if (pfd[0].revents & POLLIN) {
01470
01471 int i, what = -1;
01472
01473 read(o->sndcmd[0], &what, sizeof(what));
01474 for (i = 0; sounds[i].ind != -1; i++) {
01475 if (sounds[i].ind == what) {
01476 o->cursound = i;
01477 o->sampsent = 0;
01478 o->nosound = 1;
01479 break;
01480 }
01481 }
01482 if (sounds[i].ind == -1) {
01483 ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
01484 }
01485 }
01486 if (o->sounddev > -1) {
01487 if (pfd[1].revents & POLLIN) {
01488 read(o->sounddev, ign, sizeof(ign));
01489 }
01490 if (pfd[1].revents & POLLOUT) {
01491 send_sound(o);
01492 }
01493 }
01494 }
01495 return NULL;
01496 }
01497
01498 #endif
01499
01500
01501
01502
01503
01504
01505 static int setformat(struct chan_usbradio_pvt *o, int mode)
01506 {
01507 int fmt, desired, res, fd;
01508 char device[100];
01509
01510 if (o->sounddev >= 0) {
01511 ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
01512 close(o->sounddev);
01513 o->duplex = M_UNSET;
01514 o->sounddev = -1;
01515 }
01516 if (mode == O_CLOSE)
01517 return 0;
01518 o->lastopen = ast_tvnow();
01519 strcpy(device,"/dev/dsp");
01520 if (o->devicenum)
01521 sprintf(device,"/dev/dsp%d",o->devicenum);
01522 fd = o->sounddev = open(device, mode | O_NONBLOCK);
01523 if (fd < 0) {
01524 ast_log(LOG_WARNING, "Unable to re-open DSP device %d: %s\n", o->devicenum, strerror(errno));
01525 return -1;
01526 }
01527 if (o->owner)
01528 o->owner->fds[0] = fd;
01529
01530 #if __BYTE_ORDER == __LITTLE_ENDIAN
01531 fmt = AFMT_S16_LE;
01532 #else
01533 fmt = AFMT_S16_BE;
01534 #endif
01535 res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
01536 if (res < 0) {
01537 ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
01538 return -1;
01539 }
01540 switch (mode) {
01541 case O_RDWR:
01542 res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
01543
01544 res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
01545 if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
01546 if (option_verbose > 1)
01547 ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
01548 o->duplex = M_FULL;
01549 };
01550 break;
01551 case O_WRONLY:
01552 o->duplex = M_WRITE;
01553 break;
01554 case O_RDONLY:
01555 o->duplex = M_READ;
01556 break;
01557 }
01558
01559 fmt = 1;
01560 res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
01561 if (res < 0) {
01562 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
01563 return -1;
01564 }
01565 fmt = desired = 48000;
01566 res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
01567
01568 if (res < 0) {
01569 ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
01570 return -1;
01571 }
01572 if (fmt != desired) {
01573 if (!(o->warned & WARN_speed)) {
01574 ast_log(LOG_WARNING,
01575 "Requested %d Hz, got %d Hz -- sound may be choppy\n",
01576 desired, fmt);
01577 o->warned |= WARN_speed;
01578 }
01579 }
01580
01581
01582
01583
01584 if (o->frags) {
01585 fmt = o->frags;
01586 res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
01587 if (res < 0) {
01588 if (!(o->warned & WARN_frag)) {
01589 ast_log(LOG_WARNING,
01590 "Unable to set fragment size -- sound may be choppy\n");
01591 o->warned |= WARN_frag;
01592 }
01593 }
01594 }
01595
01596 res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
01597 res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
01598
01599 return 0;
01600 }
01601
01602
01603
01604
01605 static int usbradio_digit_begin(struct ast_channel *c, char digit)
01606 {
01607 return 0;
01608 }
01609
01610 static int usbradio_digit_end(struct ast_channel *c, char digit, unsigned int duration)
01611 {
01612
01613 ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
01614 digit, duration);
01615 return 0;
01616 }
01617
01618
01619
01620
01621 static int usbradio_text(struct ast_channel *c, const char *text)
01622 {
01623 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
01624 double tx,rx;
01625 char cnt,rxs[16],txs[16],txpl[16],rxpl[16];
01626 char pwr,*cmd;
01627
01628 cmd = alloca(strlen(text) + 10);
01629
01630
01631 if(o->debuglevel)ast_verbose(" << Console Received usbradio text %s >> \n", text);
01632
01633 cnt = sscanf(text, "%300s %15s %15s %15s %15s %1c", cmd, rxs, txs, rxpl, txpl, &pwr);
01634
01635 if (strcmp(cmd,"SETCHAN")==0)
01636 {
01637 u8 chan;
01638 chan=strtod(rxs,NULL);
01639 ppbinout(chan);
01640 if(o->debuglevel)ast_log(LOG_NOTICE,"parse usbradio SETCHAN cmd: %s chan: %i\n",text,chan);
01641 return 0;
01642 }
01643
01644 if (cnt < 6)
01645 {
01646 ast_log(LOG_ERROR,"Cannot parse usbradio text: %s\n",text);
01647 return 0;
01648 }
01649 else
01650 {
01651 if(o->debuglevel)ast_verbose(" << %s %s %s %s %s %c >> \n", cmd,rxs,txs,rxpl,txpl,pwr);
01652 }
01653
01654 if (strcmp(cmd,"SETFREQ")==0)
01655 {
01656 if(o->debuglevel)ast_log(LOG_NOTICE,"parse usbradio SETFREQ cmd: %s\n",text);
01657 tx=strtod(txs,NULL);
01658 rx=strtod(rxs,NULL);
01659 o->set_txfreq = round(tx * (double)1000000);
01660 o->set_rxfreq = round(rx * (double)1000000);
01661 o->pmrChan->txpower = (pwr == 'H');
01662 strcpy(o->set_rxctcssfreqs,rxpl);
01663 strcpy(o->set_txctcssfreqs,txpl);
01664
01665 o->b.remoted=1;
01666 xpmr_config(o);
01667 return 0;
01668 }
01669 ast_log(LOG_ERROR,"Cannot parse usbradio cmd: %s\n",text);
01670 return 0;
01671 }
01672
01673
01674 static void ring(struct chan_usbradio_pvt *o, int x)
01675 {
01676 #ifndef NEW_ASTERISK
01677 write(o->sndcmd[1], &x, sizeof(x));
01678 #endif
01679 }
01680
01681
01682
01683
01684 static int usbradio_call(struct ast_channel *c, char *dest, int timeout)
01685 {
01686 struct chan_usbradio_pvt *o = c->tech_pvt;
01687
01688 o->stophid = 0;
01689 time(&o->lasthidtime);
01690 ast_pthread_create_background(&o->hidthread, NULL, hidthread, o);
01691 ast_setstate(c, AST_STATE_UP);
01692 return 0;
01693 }
01694
01695
01696
01697
01698 static int usbradio_answer(struct ast_channel *c)
01699 {
01700 #ifndef NEW_ASTERISK
01701 struct chan_usbradio_pvt *o = c->tech_pvt;
01702 #endif
01703
01704 ast_setstate(c, AST_STATE_UP);
01705 #ifndef NEW_ASTERISK
01706 o->cursound = -1;
01707 o->nosound = 0;
01708 #endif
01709 return 0;
01710 }
01711
01712 static int usbradio_hangup(struct ast_channel *c)
01713 {
01714 struct chan_usbradio_pvt *o = c->tech_pvt;
01715
01716
01717 #ifndef NEW_ASTERISK
01718 o->cursound = -1;
01719 o->nosound = 0;
01720 #endif
01721 c->tech_pvt = NULL;
01722 o->owner = NULL;
01723 ast_module_unref(ast_module_info->self);
01724 if (o->hookstate) {
01725 if (o->autoanswer || o->autohangup) {
01726
01727 o->hookstate = 0;
01728 setformat(o, O_CLOSE);
01729 } else {
01730
01731 ring(o, AST_CONTROL_CONGESTION);
01732 }
01733 }
01734 o->stophid = 1;
01735 pthread_join(o->hidthread,NULL);
01736 return 0;
01737 }
01738
01739
01740
01741 static int usbradio_write(struct ast_channel *c, struct ast_frame *f)
01742 {
01743 struct chan_usbradio_pvt *o = c->tech_pvt;
01744
01745 traceusb2(("usbradio_write() o->nosound= %i\n",o->nosound));
01746
01747 #ifndef NEW_ASTERISK
01748
01749 if (o->nosound)
01750 return 0;
01751
01752 o->cursound = -1;
01753 #endif
01754
01755
01756
01757
01758
01759
01760
01761 #if DEBUG_CAPTURES == 1 // to write input data to a file datalen=320
01762 if (ftxcapraw && o->b.txcapraw)
01763 {
01764 i16 i, tbuff[f->datalen];
01765 for(i=0;i<f->datalen;i+=2)
01766 {
01767 tbuff[i]= ((i16*)(f->data.ptr))[i/2];
01768 tbuff[i+1]= o->txkeyed*M_Q13;
01769 }
01770 if (fwrite(tbuff,2,f->datalen,ftxcapraw) != f->datalen) {
01771 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
01772 }
01773
01774 }
01775 #endif
01776
01777
01778
01779 PmrTx(o->pmrChan,(i16*)f->data.ptr);
01780
01781 return 0;
01782 }
01783
01784 static struct ast_frame *usbradio_read(struct ast_channel *c)
01785 {
01786 int res, src, datalen, oldpttout;
01787 int cd,sd;
01788 struct chan_usbradio_pvt *o = c->tech_pvt;
01789 struct ast_frame *f = &o->read_f,*f1;
01790 struct ast_frame wf = { AST_FRAME_CONTROL };
01791 time_t now;
01792
01793 traceusb2(("usbradio_read()\n"));
01794
01795 if (o->lasthidtime)
01796 {
01797 time(&now);
01798 if ((now - o->lasthidtime) > 3)
01799 {
01800 ast_log(LOG_ERROR,"HID process has died or something!!\n");
01801 return NULL;
01802 }
01803 }
01804
01805
01806 memset(f, '\0', sizeof(struct ast_frame));
01807 f->frametype = AST_FRAME_NULL;
01808 f->src = usbradio_tech.type;
01809
01810 res = read(o->sounddev, o->usbradio_read_buf + o->readpos,
01811 sizeof(o->usbradio_read_buf) - o->readpos);
01812 if (res < 0)
01813 {
01814 if (errno != EAGAIN) return NULL;
01815 if (o->readerrs++ > READERR_THRESHOLD)
01816 {
01817 ast_log(LOG_ERROR,"Stuck USB read channel [%s], un-sticking it!\n",o->name);
01818 o->readerrs = 0;
01819 return NULL;
01820 }
01821 if (o->readerrs == 1)
01822 ast_log(LOG_WARNING,"Possibly stuck USB read channel. [%s]\n",o->name);
01823 return f;
01824 }
01825 if (o->readerrs) ast_log(LOG_WARNING,"Nope, USB read channel [%s] wasn't stuck after all.\n",o->name);
01826 o->readerrs = 0;
01827 o->readpos += res;
01828 if (o->readpos < sizeof(o->usbradio_read_buf))
01829 return f;
01830
01831 if (o->mute)
01832 return f;
01833
01834 #if DEBUG_CAPTURES == 1
01835 if ((o->b.rxcapraw && frxcapraw) && (fwrite((o->usbradio_read_buf + AST_FRIENDLY_OFFSET),1,FRAME_SIZE * 2 * 2 * 6,frxcapraw) != FRAME_SIZE * 2 * 2 * 6)) {
01836 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
01837 }
01838 #endif
01839
01840 #if 1
01841 if(o->txkeyed||o->txtestkey)
01842 {
01843 if(!o->pmrChan->txPttIn)
01844 {
01845 o->pmrChan->txPttIn=1;
01846 if(o->debuglevel) ast_log(LOG_NOTICE,"txPttIn = %i, chan %s\n",o->pmrChan->txPttIn,o->owner->name);
01847 }
01848 }
01849 else if(o->pmrChan->txPttIn)
01850 {
01851 o->pmrChan->txPttIn=0;
01852 if(o->debuglevel) ast_log(LOG_NOTICE,"txPttIn = %i, chan %s\n",o->pmrChan->txPttIn,o->owner->name);
01853 }
01854 oldpttout = o->pmrChan->txPttOut;
01855
01856 PmrRx( o->pmrChan,
01857 (i16 *)(o->usbradio_read_buf + AST_FRIENDLY_OFFSET),
01858 (i16 *)(o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET),
01859 (i16 *)(o->usbradio_write_buf_1));
01860
01861 if (oldpttout != o->pmrChan->txPttOut)
01862 {
01863 if(o->debuglevel) ast_log(LOG_NOTICE,"txPttOut = %i, chan %s\n",o->pmrChan->txPttOut,o->owner->name);
01864 kickptt(o);
01865 }
01866
01867 #if 0 // to write 48KS/s stereo tx data to a file
01868 if (!ftxoutraw) ftxoutraw = fopen(TX_CAP_OUT_FILE,"w");
01869 if (ftxoutraw) fwrite(o->usbradio_write_buf_1,1,FRAME_SIZE * 2 * 6,ftxoutraw);
01870 #endif
01871
01872 #if DEBUG_CAPTURES == 1 && XPMR_DEBUG0 == 1
01873 if ((o->b.txcap2 && ftxcaptrace) && (fwrite((o->pmrChan->ptxDebug),1,FRAME_SIZE * 2 * 16,ftxcaptrace) != FRAME_SIZE * 2 * 16)) {
01874 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
01875 }
01876 #endif
01877
01878
01879 datalen = FRAME_SIZE * 24;
01880 src = 0;
01881 while (src < datalen)
01882 {
01883
01884 int l = sizeof(o->usbradio_write_buf) - o->usbradio_write_dst;
01885
01886 if (datalen - src >= l)
01887 {
01888
01889 memcpy(o->usbradio_write_buf + o->usbradio_write_dst, o->usbradio_write_buf_1 + src, l);
01890 soundcard_writeframe(o, (short *) o->usbradio_write_buf);
01891 src += l;
01892 o->usbradio_write_dst = 0;
01893 }
01894 else
01895 {
01896
01897 l = datalen - src;
01898 memcpy(o->usbradio_write_buf + o->usbradio_write_dst, o->usbradio_write_buf_1 + src, l);
01899 src += l;
01900 o->usbradio_write_dst += l;
01901 }
01902 }
01903 #else
01904 static FILE *hInput;
01905 i16 iBuff[FRAME_SIZE*2*6];
01906
01907 o->pmrChan->b.rxCapture=1;
01908
01909 if(!hInput)
01910 {
01911 hInput = fopen("/usr/src/xpmr/testdata/rx_in.pcm","r");
01912 if(!hInput)
01913 {
01914 printf(" Input Data File Not Found.\n");
01915 return 0;
01916 }
01917 }
01918
01919 if(0==fread((void *)iBuff,2,FRAME_SIZE*2*6,hInput))exit;
01920
01921 PmrRx( o->pmrChan,
01922 (i16 *)iBuff,
01923 (i16 *)(o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET));
01924
01925 #endif
01926
01927 #if 0
01928 if (!frxoutraw) frxoutraw = fopen(RX_CAP_OUT_FILE,"w");
01929 if (frxoutraw) fwrite((o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET),1,FRAME_SIZE * 2,frxoutraw);
01930 #endif
01931
01932 #if DEBUG_CAPTURES == 1 && XPMR_DEBUG0 == 1
01933 if ((frxcaptrace && o->b.rxcap2 && o->pmrChan->b.radioactive) && (fwrite((o->pmrChan->prxDebug),1,FRAME_SIZE * 2 * 16,frxcaptrace) != FRAME_SIZE * 2 * 16 )) {
01934 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
01935 }
01936 #endif
01937
01938 cd = 0;
01939 if(o->rxcdtype==CD_HID && (o->pmrChan->rxExtCarrierDetect!=o->rxhidsq))
01940 o->pmrChan->rxExtCarrierDetect=o->rxhidsq;
01941
01942 if(o->rxcdtype==CD_HID_INVERT && (o->pmrChan->rxExtCarrierDetect==o->rxhidsq))
01943 o->pmrChan->rxExtCarrierDetect=!o->rxhidsq;
01944
01945 if( (o->rxcdtype==CD_HID && o->rxhidsq) ||
01946 (o->rxcdtype==CD_HID_INVERT && !o->rxhidsq) ||
01947 (o->rxcdtype==CD_XPMR_NOISE && o->pmrChan->rxCarrierDetect) ||
01948 (o->rxcdtype==CD_XPMR_VOX && o->pmrChan->rxCarrierDetect)
01949 )
01950 {
01951 if (!o->pmrChan->txPttOut || o->radioduplex)cd=1;
01952 }
01953 else
01954 {
01955 cd=0;
01956 }
01957
01958 if(cd!=o->rxcarrierdetect)
01959 {
01960 o->rxcarrierdetect=cd;
01961 if(o->debuglevel) ast_log(LOG_NOTICE,"rxcarrierdetect = %i, chan %s\n",cd,o->owner->name);
01962
01963 }
01964
01965 if(o->pmrChan->b.ctcssRxEnable && o->pmrChan->rxCtcss->decode!=o->rxctcssdecode)
01966 {
01967 if(o->debuglevel)ast_log(LOG_NOTICE,"rxctcssdecode = %i, chan %s\n",o->pmrChan->rxCtcss->decode,o->owner->name);
01968
01969 o->rxctcssdecode=o->pmrChan->rxCtcss->decode;
01970 strcpy(o->rxctcssfreq, o->pmrChan->rxctcssfreq);
01971 }
01972
01973 #ifndef HAVE_XPMRX
01974 if( !o->pmrChan->b.ctcssRxEnable ||
01975 ( o->pmrChan->b.ctcssRxEnable &&
01976 o->pmrChan->rxCtcss->decode>CTCSS_NULL &&
01977 o->pmrChan->smode==SMODE_CTCSS )
01978 )
01979 {
01980 sd=1;
01981 }
01982 else
01983 {
01984 sd=0;
01985 }
01986 #else
01987 if( (!o->pmrChan->b.ctcssRxEnable && !o->pmrChan->b.dcsRxEnable && !o->pmrChan->b.lmrRxEnable) ||
01988 ( o->pmrChan->b.ctcssRxEnable &&
01989 o->pmrChan->rxCtcss->decode>CTCSS_NULL &&
01990 o->pmrChan->smode==SMODE_CTCSS ) ||
01991 ( o->pmrChan->b.dcsRxEnable &&
01992 o->pmrChan->decDcs->decode > 0 &&
01993 o->pmrChan->smode==SMODE_DCS )
01994 )
01995 {
01996 sd=1;
01997 }
01998 else
01999 {
02000 sd=0;
02001 }
02002
02003 if(o->pmrChan->decDcs->decode!=o->rxdcsdecode)
02004 {
02005 if(o->debuglevel)ast_log(LOG_NOTICE,"rxdcsdecode = %s, chan %s\n",o->pmrChan->rxctcssfreq,o->owner->name);
02006
02007 o->rxdcsdecode=o->pmrChan->decDcs->decode;
02008 strcpy(o->rxctcssfreq, o->pmrChan->rxctcssfreq);
02009 }
02010
02011 if(o->pmrChan->rptnum && (o->pmrChan->pLsdCtl->cs[o->pmrChan->rptnum].b.rxkeyed != o->rxlsddecode))
02012 {
02013 if(o->debuglevel)ast_log(LOG_NOTICE,"rxLSDecode = %s, chan %s\n",o->pmrChan->rxctcssfreq,o->owner->name);
02014 o->rxlsddecode=o->pmrChan->pLsdCtl->cs[o->pmrChan->rptnum].b.rxkeyed;
02015 strcpy(o->rxctcssfreq, o->pmrChan->rxctcssfreq);
02016 }
02017
02018 if( (o->pmrChan->rptnum>0 && o->pmrChan->smode==SMODE_LSD && o->pmrChan->pLsdCtl->cs[o->pmrChan->rptnum].b.rxkeyed)||
02019 (o->pmrChan->smode==SMODE_DCS && o->pmrChan->decDcs->decode>0) )
02020 {
02021 sd=1;
02022 }
02023 #endif
02024
02025 if ( cd && sd )
02026 {
02027
02028 if(!o->rxkeyed && o->debuglevel)ast_log(LOG_NOTICE,"o->rxkeyed = 1, chan %s\n", o->owner->name);
02029 o->rxkeyed = 1;
02030 }
02031 else
02032 {
02033
02034 if(o->rxkeyed && o->debuglevel)ast_log(LOG_NOTICE,"o->rxkeyed = 0, chan %s\n",o->owner->name);
02035 o->rxkeyed = 0;
02036 }
02037
02038
02039 if (o->lastrx && (!o->rxkeyed))
02040 {
02041 o->lastrx = 0;
02042
02043 wf.subclass.integer = AST_CONTROL_RADIO_UNKEY;
02044 ast_queue_frame(o->owner, &wf);
02045 }
02046 else if ((!o->lastrx) && (o->rxkeyed))
02047 {
02048 o->lastrx = 1;
02049
02050 wf.subclass.integer = AST_CONTROL_RADIO_KEY;
02051 if(o->rxctcssdecode)
02052 {
02053 wf.data.ptr = o->rxctcssfreq;
02054 wf.datalen = strlen(o->rxctcssfreq) + 1;
02055 TRACEO(1,("AST_CONTROL_RADIO_KEY text=%s\n",o->rxctcssfreq));
02056 }
02057 ast_queue_frame(o->owner, &wf);
02058 }
02059
02060 o->readpos = AST_FRIENDLY_OFFSET;
02061 if (c->_state != AST_STATE_UP)
02062 return f;
02063
02064 f->frametype = AST_FRAME_VOICE;
02065 f->subclass.codec = AST_FORMAT_SLINEAR;
02066 f->samples = FRAME_SIZE;
02067 f->datalen = FRAME_SIZE * 2;
02068 f->data.ptr = o->usbradio_read_buf_8k + AST_FRIENDLY_OFFSET;
02069 if (o->boost != BOOST_SCALE) {
02070 int i, x;
02071 int16_t *p = (int16_t *) f->data.ptr;
02072 for (i = 0; i < f->samples; i++) {
02073 x = (p[i] * o->boost) / BOOST_SCALE;
02074 if (x > 32767)
02075 x = 32767;
02076 else if (x < -32768)
02077 x = -32768;
02078 p[i] = x;
02079 }
02080 }
02081
02082 f->offset = AST_FRIENDLY_OFFSET;
02083 if (o->dsp)
02084 {
02085 f1 = ast_dsp_process(c,o->dsp,f);
02086 if ((f1->frametype == AST_FRAME_DTMF_END) ||
02087 (f1->frametype == AST_FRAME_DTMF_BEGIN))
02088 {
02089 if ((f1->subclass.integer == 'm') || (f1->subclass.integer == 'u'))
02090 {
02091 f1->frametype = AST_FRAME_NULL;
02092 f1->subclass.integer = 0;
02093 return(f1);
02094 }
02095 if (f1->frametype == AST_FRAME_DTMF_END)
02096 ast_log(LOG_NOTICE, "Got DTMF char %c\n", f1->subclass.integer);
02097 return(f1);
02098 }
02099 }
02100 return f;
02101 }
02102
02103 static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
02104 {
02105 struct chan_usbradio_pvt *o = newchan->tech_pvt;
02106 ast_log(LOG_WARNING,"usbradio_fixup()\n");
02107 o->owner = newchan;
02108 return 0;
02109 }
02110
02111 static int usbradio_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
02112 {
02113 struct chan_usbradio_pvt *o = c->tech_pvt;
02114 int res = -1;
02115
02116 switch (cond) {
02117 case AST_CONTROL_BUSY:
02118 case AST_CONTROL_CONGESTION:
02119 case AST_CONTROL_RINGING:
02120 res = cond;
02121 break;
02122
02123 case -1:
02124 #ifndef NEW_ASTERISK
02125 o->cursound = -1;
02126 o->nosound = 0;
02127 #endif
02128 return 0;
02129
02130 case AST_CONTROL_VIDUPDATE:
02131 res = -1;
02132 break;
02133 case AST_CONTROL_HOLD:
02134 ast_verbose(" << Console Has Been Placed on Hold >> \n");
02135 ast_moh_start(c, data, o->mohinterpret);
02136 break;
02137 case AST_CONTROL_UNHOLD:
02138 ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
02139 ast_moh_stop(c);
02140 break;
02141 case AST_CONTROL_PROCEEDING:
02142 ast_verbose(" << Call Proceeding... >> \n");
02143 ast_moh_stop(c);
02144 break;
02145 case AST_CONTROL_PROGRESS:
02146 ast_verbose(" << Call Progress... >> \n");
02147 ast_moh_stop(c);
02148 break;
02149 case AST_CONTROL_RADIO_KEY:
02150 o->txkeyed = 1;
02151 if(o->debuglevel)ast_verbose(" << AST_CONTROL_RADIO_KEY Radio Transmit On. >> \n");
02152 break;
02153 case AST_CONTROL_RADIO_UNKEY:
02154 o->txkeyed = 0;
02155 if(o->debuglevel)ast_verbose(" << AST_CONTROL_RADIO_UNKEY Radio Transmit Off. >> \n");
02156 break;
02157 default:
02158 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
02159 return -1;
02160 }
02161
02162 if (res > -1)
02163 ring(o, res);
02164
02165 return 0;
02166 }
02167
02168
02169
02170
02171 static struct ast_channel *usbradio_new(struct chan_usbradio_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
02172 {
02173 struct ast_channel *c;
02174
02175 c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Radio/%s", o->name);
02176 if (c == NULL)
02177 return NULL;
02178 c->tech = &usbradio_tech;
02179 if (o->sounddev < 0)
02180 setformat(o, O_RDWR);
02181 c->fds[0] = o->sounddev;
02182 c->nativeformats = AST_FORMAT_SLINEAR;
02183 c->readformat = AST_FORMAT_SLINEAR;
02184 c->writeformat = AST_FORMAT_SLINEAR;
02185 c->tech_pvt = o;
02186
02187 if (!ast_strlen_zero(o->language))
02188 ast_string_field_set(c, language, o->language);
02189
02190
02191 if (!ast_strlen_zero(o->cid_num)) {
02192 c->caller.ani.number.valid = 1;
02193 c->caller.ani.number.str = ast_strdup(o->cid_num);
02194 }
02195 if (!ast_strlen_zero(ext)) {
02196 c->dialed.number.str = ast_strdup(ext);
02197 }
02198
02199 o->owner = c;
02200 ast_module_ref(ast_module_info->self);
02201 ast_jb_configure(c, &global_jbconf);
02202 if (state != AST_STATE_DOWN) {
02203 if (ast_pbx_start(c)) {
02204 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
02205 ast_hangup(c);
02206 o->owner = c = NULL;
02207
02208
02209 }
02210 }
02211
02212 return c;
02213 }
02214
02215
02216 static struct ast_channel *usbradio_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
02217 {
02218 struct ast_channel *c;
02219 struct chan_usbradio_pvt *o = find_desc(data);
02220
02221 TRACEO(1,("usbradio_request()\n"));
02222
02223 if (0)
02224 {
02225 ast_log(LOG_WARNING, "usbradio_request type <%s> data 0x%p <%s>\n", type, data, (char *) data);
02226 }
02227 if (o == NULL) {
02228 ast_log(LOG_NOTICE, "Device %s not found\n", (char *) data);
02229
02230 return NULL;
02231 }
02232 if ((format & AST_FORMAT_SLINEAR) == 0) {
02233 ast_log(LOG_NOTICE, "Format 0x%" PRIx64 " unsupported\n", format);
02234 return NULL;
02235 }
02236 if (o->owner) {
02237 ast_log(LOG_NOTICE, "Already have a call (chan %p) on the usb channel\n", o->owner);
02238 *cause = AST_CAUSE_BUSY;
02239 return NULL;
02240 }
02241 c = usbradio_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
02242 if (c == NULL) {
02243 ast_log(LOG_WARNING, "Unable to create new usb channel\n");
02244 return NULL;
02245 }
02246
02247 o->b.remoted=0;
02248 xpmr_config(o);
02249
02250 return c;
02251 }
02252
02253
02254 static int console_key(int fd, int argc, char *argv[])
02255 {
02256 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02257
02258 if (argc != 2)
02259 return RESULT_SHOWUSAGE;
02260 o->txtestkey = 1;
02261 return RESULT_SUCCESS;
02262 }
02263
02264
02265 static int console_unkey(int fd, int argc, char *argv[])
02266 {
02267 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02268
02269 if (argc != 2)
02270 return RESULT_SHOWUSAGE;
02271 o->txtestkey = 0;
02272 return RESULT_SUCCESS;
02273 }
02274
02275 static int radio_tune(int fd, int argc, char *argv[])
02276 {
02277 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02278 int i=0;
02279
02280 if ((argc < 2) || (argc > 4))
02281 return RESULT_SHOWUSAGE;
02282
02283 if (argc == 2)
02284 {
02285 ast_cli(fd,"Active radio interface is [%s]\n",usbradio_active);
02286 ast_cli(fd,"Output A is currently set to ");
02287 if(o->txmixa==TX_OUT_COMPOSITE)ast_cli(fd,"composite.\n");
02288 else if (o->txmixa==TX_OUT_VOICE)ast_cli(fd,"voice.\n");
02289 else if (o->txmixa==TX_OUT_LSD)ast_cli(fd,"tone.\n");
02290 else if (o->txmixa==TX_OUT_AUX)ast_cli(fd,"auxvoice.\n");
02291 else ast_cli(fd,"off.\n");
02292
02293 ast_cli(fd,"Output B is currently set to ");
02294 if(o->txmixb==TX_OUT_COMPOSITE)ast_cli(fd,"composite.\n");
02295 else if (o->txmixb==TX_OUT_VOICE)ast_cli(fd,"voice.\n");
02296 else if (o->txmixb==TX_OUT_LSD)ast_cli(fd,"tone.\n");
02297 else if (o->txmixb==TX_OUT_AUX)ast_cli(fd,"auxvoice.\n");
02298 else ast_cli(fd,"off.\n");
02299
02300 ast_cli(fd,"Tx Voice Level currently set to %d\n",o->txmixaset);
02301 ast_cli(fd,"Tx Tone Level currently set to %d\n",o->txctcssadj);
02302 ast_cli(fd,"Rx Squelch currently set to %d\n",o->rxsquelchadj);
02303 ast_cli(fd,"Device String is %s\n",o->devstr);
02304 return RESULT_SHOWUSAGE;
02305 }
02306
02307 o->pmrChan->b.tuning=1;
02308
02309 if (!strcasecmp(argv[2],"rxnoise")) tune_rxinput(fd,o);
02310 else if (!strcasecmp(argv[2],"rxvoice")) tune_rxvoice(fd,o);
02311 else if (!strcasecmp(argv[2],"rxtone")) tune_rxctcss(fd,o);
02312 else if (!strcasecmp(argv[2],"rxsquelch"))
02313 {
02314 if (argc == 3)
02315 {
02316 ast_cli(fd,"Current Signal Strength is %d\n",((32767-o->pmrChan->rxRssi)*1000/32767));
02317 ast_cli(fd,"Current Squelch setting is %d\n",o->rxsquelchadj);
02318
02319
02320 } else {
02321 i = atoi(argv[3]);
02322 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02323 ast_cli(fd,"Changed Squelch setting to %d\n",i);
02324 o->rxsquelchadj = i;
02325 *(o->pmrChan->prxSquelchAdjust)= ((999 - i) * 32767) / 1000;
02326 }
02327 }
02328 else if (!strcasecmp(argv[2],"txvoice")) {
02329 i = 0;
02330
02331 if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) &&
02332 (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE)
02333 )
02334 {
02335 ast_log(LOG_ERROR,"No txvoice output configured.\n");
02336 }
02337 else if (argc == 3)
02338 {
02339 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02340 ast_cli(fd,"Current txvoice setting on Channel A is %d\n",o->txmixaset);
02341 else
02342 ast_cli(fd,"Current txvoice setting on Channel B is %d\n",o->txmixbset);
02343 }
02344 else
02345 {
02346 i = atoi(argv[3]);
02347 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02348
02349 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02350 {
02351 o->txmixaset=i;
02352 ast_cli(fd,"Changed txvoice setting on Channel A to %d\n",o->txmixaset);
02353 }
02354 else
02355 {
02356 o->txmixbset=i;
02357 ast_cli(fd,"Changed txvoice setting on Channel B to %d\n",o->txmixbset);
02358 }
02359 mixer_write(o);
02360 mult_set(o);
02361 ast_cli(fd,"Changed Tx Voice Output setting to %d\n",i);
02362 }
02363 o->pmrChan->b.txCtcssInhibit=1;
02364 tune_txoutput(o,i,fd);
02365 o->pmrChan->b.txCtcssInhibit=0;
02366 }
02367 else if (!strcasecmp(argv[2],"txall")) {
02368 i = 0;
02369
02370 if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) &&
02371 (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE)
02372 )
02373 {
02374 ast_log(LOG_ERROR,"No txvoice output configured.\n");
02375 }
02376 else if (argc == 3)
02377 {
02378 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02379 ast_cli(fd,"Current txvoice setting on Channel A is %d\n",o->txmixaset);
02380 else
02381 ast_cli(fd,"Current txvoice setting on Channel B is %d\n",o->txmixbset);
02382 }
02383 else
02384 {
02385 i = atoi(argv[3]);
02386 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02387
02388 if((o->txmixa==TX_OUT_VOICE)||(o->txmixa==TX_OUT_COMPOSITE))
02389 {
02390 o->txmixaset=i;
02391 ast_cli(fd,"Changed txvoice setting on Channel A to %d\n",o->txmixaset);
02392 }
02393 else
02394 {
02395 o->txmixbset=i;
02396 ast_cli(fd,"Changed txvoice setting on Channel B to %d\n",o->txmixbset);
02397 }
02398 mixer_write(o);
02399 mult_set(o);
02400 ast_cli(fd,"Changed Tx Voice Output setting to %d\n",i);
02401 }
02402 tune_txoutput(o,i,fd);
02403 }
02404 else if (!strcasecmp(argv[2],"auxvoice")) {
02405 i = 0;
02406 if( (o->txmixa!=TX_OUT_AUX) && (o->txmixb!=TX_OUT_AUX))
02407 {
02408 ast_log(LOG_WARNING,"No auxvoice output configured.\n");
02409 }
02410 else if (argc == 3)
02411 {
02412 if(o->txmixa==TX_OUT_AUX)
02413 ast_cli(fd,"Current auxvoice setting on Channel A is %d\n",o->txmixaset);
02414 else
02415 ast_cli(fd,"Current auxvoice setting on Channel B is %d\n",o->txmixbset);
02416 }
02417 else
02418 {
02419 i = atoi(argv[3]);
02420 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02421 if(o->txmixa==TX_OUT_AUX)
02422 {
02423 o->txmixbset=i;
02424 ast_cli(fd,"Changed auxvoice setting on Channel A to %d\n",o->txmixaset);
02425 }
02426 else
02427 {
02428 o->txmixbset=i;
02429 ast_cli(fd,"Changed auxvoice setting on Channel B to %d\n",o->txmixbset);
02430 }
02431 mixer_write(o);
02432 mult_set(o);
02433 }
02434
02435 }
02436 else if (!strcasecmp(argv[2],"txtone"))
02437 {
02438 if (argc == 3)
02439 ast_cli(fd,"Current Tx CTCSS modulation setting = %d\n",o->txctcssadj);
02440 else
02441 {
02442 i = atoi(argv[3]);
02443 if ((i < 0) || (i > 999)) return RESULT_SHOWUSAGE;
02444 o->txctcssadj = i;
02445 set_txctcss_level(o);
02446 ast_cli(fd,"Changed Tx CTCSS modulation setting to %i\n",i);
02447 }
02448 o->txtestkey=1;
02449 usleep(5000000);
02450 o->txtestkey=0;
02451 }
02452 else if (!strcasecmp(argv[2],"dump")) pmrdump(o);
02453 else if (!strcasecmp(argv[2],"nocap"))
02454 {
02455 ast_cli(fd,"File capture (trace) was rx=%d tx=%d and now off.\n",o->b.rxcap2,o->b.txcap2);
02456 ast_cli(fd,"File capture (raw) was rx=%d tx=%d and now off.\n",o->b.rxcapraw,o->b.txcapraw);
02457 o->b.rxcapraw=o->b.txcapraw=o->b.rxcap2=o->b.txcap2=o->pmrChan->b.rxCapture=o->pmrChan->b.txCapture=0;
02458 if (frxcapraw) { fclose(frxcapraw); frxcapraw = NULL; }
02459 if (frxcaptrace) { fclose(frxcaptrace); frxcaptrace = NULL; }
02460 if (frxoutraw) { fclose(frxoutraw); frxoutraw = NULL; }
02461 if (ftxcapraw) { fclose(ftxcapraw); ftxcapraw = NULL; }
02462 if (ftxcaptrace) { fclose(ftxcaptrace); ftxcaptrace = NULL; }
02463 if (ftxoutraw) { fclose(ftxoutraw); ftxoutraw = NULL; }
02464 }
02465 else if (!strcasecmp(argv[2],"rxtracecap"))
02466 {
02467 if (!frxcaptrace) frxcaptrace= fopen(RX_CAP_TRACE_FILE,"w");
02468 ast_cli(fd,"Trace rx on.\n");
02469 o->b.rxcap2=o->pmrChan->b.rxCapture=1;
02470 }
02471 else if (!strcasecmp(argv[2],"txtracecap"))
02472 {
02473 if (!ftxcaptrace) ftxcaptrace= fopen(TX_CAP_TRACE_FILE,"w");
02474 ast_cli(fd,"Trace tx on.\n");
02475 o->b.txcap2=o->pmrChan->b.txCapture=1;
02476 }
02477 else if (!strcasecmp(argv[2],"rxcap"))
02478 {
02479 if (!frxcapraw) frxcapraw = fopen(RX_CAP_RAW_FILE,"w");
02480 ast_cli(fd,"cap rx raw on.\n");
02481 o->b.rxcapraw=1;
02482 }
02483 else if (!strcasecmp(argv[2],"txcap"))
02484 {
02485 if (!ftxcapraw) ftxcapraw = fopen(TX_CAP_RAW_FILE,"w");
02486 ast_cli(fd,"cap tx raw on.\n");
02487 o->b.txcapraw=1;
02488 }
02489 else if (!strcasecmp(argv[2],"save"))
02490 {
02491 tune_write(o);
02492 ast_cli(fd,"Saved radio tuning settings to usbradio_tune_%s.conf\n",o->name);
02493 }
02494 else if (!strcasecmp(argv[2],"load"))
02495 {
02496 ast_mutex_lock(&o->eepromlock);
02497 while(o->eepromctl)
02498 {
02499 ast_mutex_unlock(&o->eepromlock);
02500 usleep(10000);
02501 ast_mutex_lock(&o->eepromlock);
02502 }
02503 o->eepromctl = 1;
02504 ast_mutex_unlock(&o->eepromlock);
02505
02506 ast_cli(fd,"Requesting loading of tuning settings from EEPROM for channel %s\n",o->name);
02507 }
02508 else
02509 {
02510 o->pmrChan->b.tuning=0;
02511 return RESULT_SHOWUSAGE;
02512 }
02513 o->pmrChan->b.tuning=0;
02514 return RESULT_SUCCESS;
02515 }
02516
02517
02518
02519
02520
02521
02522 static int set_txctcss_level(struct chan_usbradio_pvt *o)
02523 {
02524 if (o->txmixa == TX_OUT_LSD)
02525 {
02526
02527 o->txmixaset=o->txctcssadj;
02528 mixer_write(o);
02529 mult_set(o);
02530 }
02531 else if (o->txmixb == TX_OUT_LSD)
02532 {
02533
02534 o->txmixbset=o->txctcssadj;
02535 mixer_write(o);
02536 mult_set(o);
02537 }
02538 else
02539 {
02540 *o->pmrChan->ptxCtcssAdjust=(o->txctcssadj * M_Q8) / 1000;
02541 }
02542 return 0;
02543 }
02544
02545
02546
02547 static int radio_set_debug(int fd, int argc, char *argv[])
02548 {
02549 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02550
02551 o->debuglevel=1;
02552 ast_cli(fd,"usbradio debug on.\n");
02553 return RESULT_SUCCESS;
02554 }
02555
02556 static int radio_set_debug_off(int fd, int argc, char *argv[])
02557 {
02558 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02559
02560 o->debuglevel=0;
02561 ast_cli(fd,"usbradio debug off.\n");
02562 return RESULT_SUCCESS;
02563 }
02564
02565 static int radio_active(int fd, int argc, char *argv[])
02566 {
02567 if (argc == 2)
02568 ast_cli(fd, "active (command) USB Radio device is [%s]\n", usbradio_active);
02569 else if (argc != 3)
02570 return RESULT_SHOWUSAGE;
02571 else {
02572 struct chan_usbradio_pvt *o;
02573 if (strcmp(argv[2], "show") == 0) {
02574 for (o = usbradio_default.next; o; o = o->next)
02575 ast_cli(fd, "device [%s] exists\n", o->name);
02576 return RESULT_SUCCESS;
02577 }
02578 o = find_desc(argv[2]);
02579 if (o == NULL)
02580 ast_cli(fd, "No device [%s] exists\n", argv[2]);
02581 else
02582 {
02583 struct chan_usbradio_pvt *ao;
02584 for (ao = usbradio_default.next; ao && ao->name ; ao = ao->next)ao->pmrChan->b.radioactive=0;
02585 usbradio_active = o->name;
02586 o->pmrChan->b.radioactive=1;
02587 }
02588 }
02589 return RESULT_SUCCESS;
02590 }
02591
02592
02593
02594 static int radio_set_xpmr_debug(int fd, int argc, char *argv[])
02595 {
02596 struct chan_usbradio_pvt *o = find_desc(usbradio_active);
02597
02598 if (argc == 4)
02599 {
02600 int i;
02601 i = atoi(argv[3]);
02602 if ((i >= 0) && (i <= 100))
02603 {
02604 o->pmrChan->tracelevel=i;
02605 }
02606 }
02607
02608 ast_cli(fd,"usbradio xdebug on tracelevel %i\n",o->pmrChan->tracelevel);
02609
02610 return RESULT_SUCCESS;
02611 }
02612
02613
02614 static char key_usage[] =
02615 "Usage: radio key\n"
02616 " Simulates COR active.\n";
02617
02618 static char unkey_usage[] =
02619 "Usage: radio unkey\n"
02620 " Simulates COR un-active.\n";
02621
02622 static char active_usage[] =
02623 "Usage: radio active [device-name]\n"
02624 " If used without a parameter, displays which device is the current\n"
02625 "one being commanded. If a device is specified, the commanded radio device is changed\n"
02626 "to the device specified.\n";
02627
02628
02629
02630 static char radio_tune_usage[] =
02631 "Usage: radio tune <function>\n"
02632 " rxnoise\n"
02633 " rxvoice\n"
02634 " rxtone\n"
02635 " rxsquelch [newsetting]\n"
02636 " txvoice [newsetting]\n"
02637 " txtone [newsetting]\n"
02638 " auxvoice [newsetting]\n"
02639 " save (settings to tuning file)\n"
02640 " load (tuning settings from EEPROM)\n"
02641 "\n All [newsetting]'s are values 0-999\n\n";
02642
02643 #ifndef NEW_ASTERISK
02644
02645 static struct ast_cli_entry cli_usbradio[] = {
02646 { { "radio", "key", NULL },
02647 console_key, "Simulate Rx Signal Present",
02648 key_usage, NULL, NULL},
02649
02650 { { "radio", "unkey", NULL },
02651 console_unkey, "Simulate Rx Signal Lusb",
02652 unkey_usage, NULL, NULL },
02653
02654 { { "radio", "tune", NULL },
02655 radio_tune, "Radio Tune",
02656 radio_tune_usage, NULL, NULL },
02657
02658 { { "radio", "set", "debug", NULL },
02659 radio_set_debug, "Radio Debug",
02660 radio_tune_usage, NULL, NULL },
02661
02662 { { "radio", "set", "debug", "off", NULL },
02663 radio_set_debug_off, "Radio Debug",
02664 radio_tune_usage, NULL, NULL },
02665
02666 { { "radio", "active", NULL },
02667 radio_active, "Change commanded device",
02668 active_usage, NULL, NULL },
02669
02670 { { "radio", "set", "xdebug", NULL },
02671 radio_set_xpmr_debug, "Radio set xpmr debug level",
02672 active_usage, NULL, NULL },
02673
02674 };
02675 #endif
02676
02677
02678
02679
02680 #if 0
02681 static void store_callerid(struct chan_usbradio_pvt *o, char *s)
02682 {
02683 ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
02684 }
02685 #endif
02686
02687 static void store_rxdemod(struct chan_usbradio_pvt *o, const char *s)
02688 {
02689 if (!strcasecmp(s,"no")){
02690 o->rxdemod = RX_AUDIO_NONE;
02691 }
02692 else if (!strcasecmp(s,"speaker")){
02693 o->rxdemod = RX_AUDIO_SPEAKER;
02694 }
02695 else if (!strcasecmp(s,"flat")){
02696 o->rxdemod = RX_AUDIO_FLAT;
02697 }
02698 else {
02699 ast_log(LOG_WARNING,"Unrecognized rxdemod parameter: %s\n",s);
02700 }
02701
02702
02703 }
02704
02705
02706 static void store_txmixa(struct chan_usbradio_pvt *o, const char *s)
02707 {
02708 if (!strcasecmp(s,"no")){
02709 o->txmixa = TX_OUT_OFF;
02710 }
02711 else if (!strcasecmp(s,"voice")){
02712 o->txmixa = TX_OUT_VOICE;
02713 }
02714 else if (!strcasecmp(s,"tone")){
02715 o->txmixa = TX_OUT_LSD;
02716 }
02717 else if (!strcasecmp(s,"composite")){
02718 o->txmixa = TX_OUT_COMPOSITE;
02719 }
02720 else if (!strcasecmp(s,"auxvoice")){
02721 o->txmixa = TX_OUT_AUX;
02722 }
02723 else {
02724 ast_log(LOG_WARNING,"Unrecognized txmixa parameter: %s\n",s);
02725 }
02726
02727
02728 }
02729
02730 static void store_txmixb(struct chan_usbradio_pvt *o, const char *s)
02731 {
02732 if (!strcasecmp(s,"no")){
02733 o->txmixb = TX_OUT_OFF;
02734 }
02735 else if (!strcasecmp(s,"voice")){
02736 o->txmixb = TX_OUT_VOICE;
02737 }
02738 else if (!strcasecmp(s,"tone")){
02739 o->txmixb = TX_OUT_LSD;
02740 }
02741 else if (!strcasecmp(s,"composite")){
02742 o->txmixb = TX_OUT_COMPOSITE;
02743 }
02744 else if (!strcasecmp(s,"auxvoice")){
02745 o->txmixb = TX_OUT_AUX;
02746 }
02747 else {
02748 ast_log(LOG_WARNING,"Unrecognized txmixb parameter: %s\n",s);
02749 }
02750
02751
02752 }
02753
02754
02755 static void store_rxcdtype(struct chan_usbradio_pvt *o, const char *s)
02756 {
02757 if (!strcasecmp(s,"no")){
02758 o->rxcdtype = CD_IGNORE;
02759 }
02760 else if (!strcasecmp(s,"usb")){
02761 o->rxcdtype = CD_HID;
02762 }
02763 else if (!strcasecmp(s,"dsp")){
02764 o->rxcdtype = CD_XPMR_NOISE;
02765 }
02766 else if (!strcasecmp(s,"vox")){
02767 o->rxcdtype = CD_XPMR_VOX;
02768 }
02769 else if (!strcasecmp(s,"usbinvert")){
02770 o->rxcdtype = CD_HID_INVERT;
02771 }
02772 else {
02773 ast_log(LOG_WARNING,"Unrecognized rxcdtype parameter: %s\n",s);
02774 }
02775
02776
02777 }
02778
02779
02780 static void store_rxsdtype(struct chan_usbradio_pvt *o, const char *s)
02781 {
02782 if (!strcasecmp(s,"no") || !strcasecmp(s,"SD_IGNORE")){
02783 o->rxsdtype = SD_IGNORE;
02784 }
02785 else if (!strcasecmp(s,"usb") || !strcasecmp(s,"SD_HID")){
02786 o->rxsdtype = SD_HID;
02787 }
02788 else if (!strcasecmp(s,"usbinvert") || !strcasecmp(s,"SD_HID_INVERT")){
02789 o->rxsdtype = SD_HID_INVERT;
02790 }
02791 else if (!strcasecmp(s,"software") || !strcasecmp(s,"SD_XPMR")){
02792 o->rxsdtype = SD_XPMR;
02793 }
02794 else {
02795 ast_log(LOG_WARNING,"Unrecognized rxsdtype parameter: %s\n",s);
02796 }
02797
02798
02799 }
02800
02801
02802 static void store_rxgain(struct chan_usbradio_pvt *o, const char *s)
02803 {
02804 float f;
02805 sscanf(s, "%30f", &f);
02806 o->rxgain = f;
02807
02808 }
02809
02810
02811 static void store_rxvoiceadj(struct chan_usbradio_pvt *o, const char *s)
02812 {
02813 float f;
02814 sscanf(s, "%30f", &f);
02815 o->rxvoiceadj = f;
02816
02817 }
02818
02819
02820 static void store_rxctcssadj(struct chan_usbradio_pvt *o, const char *s)
02821 {
02822 float f;
02823 sscanf(s, "%30f", &f);
02824 o->rxctcssadj = f;
02825
02826 }
02827
02828
02829 static void store_txtoctype(struct chan_usbradio_pvt *o, const char *s)
02830 {
02831 if (!strcasecmp(s,"no") || !strcasecmp(s,"TOC_NONE")){
02832 o->txtoctype = TOC_NONE;
02833 }
02834 else if (!strcasecmp(s,"phase") || !strcasecmp(s,"TOC_PHASE")){
02835 o->txtoctype = TOC_PHASE;
02836 }
02837 else if (!strcasecmp(s,"notone") || !strcasecmp(s,"TOC_NOTONE")){
02838 o->txtoctype = TOC_NOTONE;
02839 }
02840 else {
02841 ast_log(LOG_WARNING,"Unrecognized txtoctype parameter: %s\n",s);
02842 }
02843 }
02844
02845
02846 static void tune_txoutput(struct chan_usbradio_pvt *o, int value, int fd)
02847 {
02848 o->txtestkey=1;
02849 o->pmrChan->txPttIn=1;
02850 TxTestTone(o->pmrChan, 1);
02851 if (fd > 0) ast_cli(fd,"Tone output starting on channel %s...\n",o->name);
02852 usleep(5000000);
02853 TxTestTone(o->pmrChan, 0);
02854 if (fd > 0) ast_cli(fd,"Tone output ending on channel %s...\n",o->name);
02855 o->pmrChan->txPttIn=0;
02856 o->txtestkey=0;
02857 }
02858
02859
02860 static void tune_rxinput(int fd, struct chan_usbradio_pvt *o)
02861 {
02862 const int target=23000;
02863 const int tolerance=2000;
02864 const int settingmin=1;
02865 const int settingstart=2;
02866 const int maxtries=12;
02867
02868 float settingmax;
02869
02870 int setting=0, tries=0, tmpdiscfactor, meas;
02871 int tunetype=0;
02872
02873 settingmax = o->micmax;
02874
02875 if(o->pmrChan->rxDemod)tunetype=1;
02876 o->pmrChan->b.tuning=1;
02877
02878 setting = settingstart;
02879
02880 ast_cli(fd,"tune rxnoise maxtries=%i, target=%i, tolerance=%i\n",maxtries,target,tolerance);
02881
02882 while(tries<maxtries)
02883 {
02884 setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL,setting,0);
02885 setamixer(o->devicenum,MIXER_PARAM_MIC_BOOST,o->rxboostset,0);
02886
02887 usleep(100000);
02888 if(o->rxcdtype!=CD_XPMR_NOISE || o->rxdemod==RX_AUDIO_SPEAKER)
02889 {
02890
02891 o->pmrChan->spsMeasure->source = o->pmrChan->spsRx->source;
02892 o->pmrChan->spsMeasure->discfactor=2000;
02893 o->pmrChan->spsMeasure->enabled=1;
02894 o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0;
02895 usleep(400000);
02896 meas=o->pmrChan->spsMeasure->apeak;
02897 o->pmrChan->spsMeasure->enabled=0;
02898 }
02899 else
02900 {
02901
02902 tmpdiscfactor=o->pmrChan->spsRx->discfactor;
02903 o->pmrChan->spsRx->discfactor=(i16)2000;
02904 o->pmrChan->spsRx->discounteru=o->pmrChan->spsRx->discounterl=0;
02905 o->pmrChan->spsRx->amax=o->pmrChan->spsRx->amin=0;
02906 usleep(200000);
02907 meas=o->pmrChan->rxRssi;
02908 o->pmrChan->spsRx->discfactor=tmpdiscfactor;
02909 o->pmrChan->spsRx->discounteru=o->pmrChan->spsRx->discounterl=0;
02910 o->pmrChan->spsRx->amax=o->pmrChan->spsRx->amin=0;
02911 }
02912 if(!meas)meas++;
02913 ast_cli(fd,"tries=%i, setting=%i, meas=%i\n",tries,setting,meas);
02914
02915 if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){
02916 setting=setting*target/meas;
02917 }
02918 else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) )
02919 {
02920 break;
02921 }
02922
02923 if(setting<settingmin)setting=settingmin;
02924 else if(setting>settingmax)setting=settingmax;
02925
02926 tries++;
02927 }
02928 ast_cli(fd,"DONE tries=%i, setting=%i, meas=%i\n",tries,
02929 (setting * 1000) / o->micmax,meas);
02930 if( meas<(target-tolerance) || meas>(target+tolerance) ){
02931 ast_cli(fd,"ERROR: RX INPUT ADJUST FAILED.\n");
02932 }else{
02933 ast_cli(fd,"INFO: RX INPUT ADJUST SUCCESS.\n");
02934 o->rxmixerset=(setting * 1000) / o->micmax;
02935 }
02936 o->pmrChan->b.tuning=0;
02937 }
02938
02939
02940 static void tune_rxvoice(int fd, struct chan_usbradio_pvt *o)
02941 {
02942 const int target=7200;
02943 const int tolerance=360;
02944 const float settingmin=0.1;
02945 const float settingmax=4;
02946 const float settingstart=1;
02947 const int maxtries=12;
02948
02949 float setting;
02950
02951 int tries=0, meas;
02952
02953 ast_cli(fd,"INFO: RX VOICE ADJUST START.\n");
02954 ast_cli(fd,"target=%i tolerance=%i \n",target,tolerance);
02955
02956 o->pmrChan->b.tuning=1;
02957 if(!o->pmrChan->spsMeasure)
02958 ast_cli(fd,"ERROR: NO MEASURE BLOCK.\n");
02959
02960 if(!o->pmrChan->spsMeasure->source || !o->pmrChan->prxVoiceAdjust )
02961 ast_cli(fd,"ERROR: NO SOURCE OR MEASURE SETTING.\n");
02962
02963 o->pmrChan->spsMeasure->source=o->pmrChan->spsRxOut->sink;
02964 o->pmrChan->spsMeasure->enabled=1;
02965 o->pmrChan->spsMeasure->discfactor=1000;
02966
02967 setting=settingstart;
02968
02969
02970
02971 while(tries<maxtries)
02972 {
02973 *(o->pmrChan->prxVoiceAdjust)=setting*M_Q8;
02974 usleep(10000);
02975 o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0;
02976 usleep(1000000);
02977 meas = o->pmrChan->spsMeasure->apeak;
02978 ast_cli(fd,"tries=%i, setting=%f, meas=%i\n",tries,setting,meas);
02979
02980 if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){
02981 setting=setting*target/meas;
02982 }
02983 else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) )
02984 {
02985 break;
02986 }
02987 if(setting<settingmin)setting=settingmin;
02988 else if(setting>settingmax)setting=settingmax;
02989
02990 tries++;
02991 }
02992
02993 o->pmrChan->spsMeasure->enabled=0;
02994
02995 ast_cli(fd,"DONE tries=%i, setting=%f, meas=%f\n",tries,setting,(float)meas);
02996 if( meas<(target-tolerance) || meas>(target+tolerance) ){
02997 ast_cli(fd,"ERROR: RX VOICE GAIN ADJUST FAILED.\n");
02998 }else{
02999 ast_cli(fd,"INFO: RX VOICE GAIN ADJUST SUCCESS.\n");
03000 o->rxvoiceadj=setting;
03001 }
03002 o->pmrChan->b.tuning=0;
03003 }
03004
03005
03006 static void tune_rxctcss(int fd, struct chan_usbradio_pvt *o)
03007 {
03008 const int target=2400;
03009 const int tolerance=100;
03010 const float settingmin=0.1;
03011 const float settingmax=8;
03012 const float settingstart=1;
03013 const int maxtries=12;
03014
03015 float setting;
03016 int tries=0, meas;
03017
03018 ast_cli(fd,"INFO: RX CTCSS ADJUST START.\n");
03019 ast_cli(fd,"target=%i tolerance=%i \n",target,tolerance);
03020
03021 o->pmrChan->b.tuning=1;
03022 o->pmrChan->spsMeasure->source=o->pmrChan->prxCtcssMeasure;
03023 o->pmrChan->spsMeasure->discfactor=400;
03024 o->pmrChan->spsMeasure->enabled=1;
03025
03026 setting=settingstart;
03027
03028 while(tries<maxtries)
03029 {
03030 *(o->pmrChan->prxCtcssAdjust)=setting*M_Q8;
03031 usleep(10000);
03032 o->pmrChan->spsMeasure->amax = o->pmrChan->spsMeasure->amin = 0;
03033 usleep(500000);
03034 meas = o->pmrChan->spsMeasure->apeak;
03035 ast_cli(fd,"tries=%i, setting=%f, meas=%i\n",tries,setting,meas);
03036
03037 if( meas<(target-tolerance) || meas>(target+tolerance) || tries<3){
03038 setting=setting*target/meas;
03039 }
03040 else if(tries>4 && meas>(target-tolerance) && meas<(target+tolerance) )
03041 {
03042 break;
03043 }
03044 if(setting<settingmin)setting=settingmin;
03045 else if(setting>settingmax)setting=settingmax;
03046
03047 tries++;
03048 }
03049 o->pmrChan->spsMeasure->enabled=0;
03050 ast_cli(fd,"DONE tries=%i, setting=%f, meas=%f\n",tries,setting,(float)meas);
03051 if( meas<(target-tolerance) || meas>(target+tolerance) ){
03052 ast_cli(fd,"ERROR: RX CTCSS GAIN ADJUST FAILED.\n");
03053 }else{
03054 ast_cli(fd,"INFO: RX CTCSS GAIN ADJUST SUCCESS.\n");
03055 o->rxctcssadj=setting;
03056 }
03057 o->pmrChan->b.tuning=0;
03058 }
03059
03060
03061
03062 static void tune_write(struct chan_usbradio_pvt *o)
03063 {
03064 FILE *fp;
03065 char fname[200];
03066
03067 snprintf(fname,sizeof(fname) - 1,"/etc/asterisk/usbradio_tune_%s.conf",o->name);
03068 fp = fopen(fname,"w");
03069
03070 fprintf(fp,"[%s]\n",o->name);
03071
03072 fprintf(fp,"; name=%s\n",o->name);
03073 fprintf(fp,"; devicenum=%i\n",o->devicenum);
03074 fprintf(fp,"devstr=%s\n",o->devstr);
03075 fprintf(fp,"rxmixerset=%i\n",o->rxmixerset);
03076 fprintf(fp,"txmixaset=%i\n",o->txmixaset);
03077 fprintf(fp,"txmixbset=%i\n",o->txmixbset);
03078 fprintf(fp,"rxvoiceadj=%f\n",o->rxvoiceadj);
03079 fprintf(fp,"rxctcssadj=%f\n",o->rxctcssadj);
03080 fprintf(fp,"txctcssadj=%i\n",o->txctcssadj);
03081 fprintf(fp,"rxsquelchadj=%i\n",o->rxsquelchadj);
03082 fclose(fp);
03083
03084 if(o->wanteeprom)
03085 {
03086 ast_mutex_lock(&o->eepromlock);
03087 while(o->eepromctl)
03088 {
03089 ast_mutex_unlock(&o->eepromlock);
03090 usleep(10000);
03091 ast_mutex_lock(&o->eepromlock);
03092 }
03093 o->eeprom[EEPROM_RXMIXERSET] = o->rxmixerset;
03094 o->eeprom[EEPROM_TXMIXASET] = o->txmixaset;
03095 o->eeprom[EEPROM_TXMIXBSET] = o->txmixbset;
03096 memcpy(&o->eeprom[EEPROM_RXVOICEADJ],&o->rxvoiceadj,sizeof(float));
03097 memcpy(&o->eeprom[EEPROM_RXCTCSSADJ],&o->rxctcssadj,sizeof(float));
03098 o->eeprom[EEPROM_TXCTCSSADJ] = o->txctcssadj;
03099 o->eeprom[EEPROM_RXSQUELCHADJ] = o->rxsquelchadj;
03100 o->eepromctl = 2;
03101 ast_mutex_unlock(&o->eepromlock);
03102 }
03103 }
03104
03105 static void mixer_write(struct chan_usbradio_pvt *o)
03106 {
03107 setamixer(o->devicenum,MIXER_PARAM_MIC_PLAYBACK_SW,0,0);
03108 setamixer(o->devicenum,MIXER_PARAM_MIC_PLAYBACK_VOL,0,0);
03109 setamixer(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_SW,1,0);
03110 setamixer(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_VOL,
03111 o->txmixaset * o->spkrmax / 1000,
03112 o->txmixbset * o->spkrmax / 1000);
03113 setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL,
03114 o->rxmixerset * o->micmax / 1000,0);
03115 setamixer(o->devicenum,MIXER_PARAM_MIC_BOOST,o->rxboostset,0);
03116 setamixer(o->devicenum,MIXER_PARAM_MIC_CAPTURE_SW,1,0);
03117 }
03118
03119
03120
03121 static void mult_set(struct chan_usbradio_pvt *o)
03122 {
03123
03124 if(o->pmrChan->spsTxOutA) {
03125 o->pmrChan->spsTxOutA->outputGain =
03126 mult_calc((o->txmixaset * 152) / 1000);
03127 }
03128 if(o->pmrChan->spsTxOutB){
03129 o->pmrChan->spsTxOutB->outputGain =
03130 mult_calc((o->txmixbset * 152) / 1000);
03131 }
03132 }
03133
03134
03135
03136 static int mult_calc(int value)
03137 {
03138 const int multx=M_Q8;
03139 int pot,mult;
03140
03141 pot=((int)(value/4)*4)+2;
03142 mult = multx-( ( multx * (3-(value%4)) ) / (pot+2) );
03143 return(mult);
03144 }
03145
03146 #define pd(x) {printf(#x" = %d\n",x);}
03147 #define pp(x) {printf(#x" = %p\n",x);}
03148 #define ps(x) {printf(#x" = %s\n",x);}
03149 #define pf(x) {printf(#x" = %f\n",x);}
03150
03151
03152 #if 0
03153
03154
03155
03156
03157
03158
03159 static int usbhider(struct chan_usbradio_pvt *o, int opt)
03160 {
03161 unsigned char buf[4];
03162 char lastrx, txtmp;
03163
03164 if(opt)
03165 {
03166 struct usb_device *usb_dev;
03167
03168 usb_dev = hid_device_init(o->devstr);
03169 if (usb_dev == NULL) {
03170 ast_log(LOG_ERROR,"USB HID device not found\n");
03171 return -1;
03172 }
03173 o->usb_handle = usb_open(usb_dev);
03174 if (o->usb_handle == NULL) {
03175 ast_log(LOG_ERROR,"Not able to open USB device\n");
03176 return -1;
03177 }
03178 if (usb_claim_interface(o->usb_handle,C108_HID_INTERFACE) < 0)
03179 {
03180 if (usb_detach_kernel_driver_np(o->usb_handle,C108_HID_INTERFACE) < 0) {
03181 ast_log(LOG_ERROR,"Not able to detach the USB device\n");
03182 return -1;
03183 }
03184 if (usb_claim_interface(o->usb_handle,C108_HID_INTERFACE) < 0) {
03185 ast_log(LOG_ERROR,"Not able to claim the USB device\n");
03186 return -1;
03187 }
03188 }
03189
03190 memset(buf,0,sizeof(buf));
03191 buf[2] = o->hid_gpio_ctl;
03192 buf[1] = 0;
03193 hid_set_outputs(o->usb_handle,buf);
03194 memcpy(bufsave,buf,sizeof(buf));
03195
03196 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
03197 o->lasttx=0;
03198 }
03199
03200
03201 txtmp=o->pmrChan->txPttOut;
03202
03203 if (o->lasttx != txtmp)
03204 {
03205 o->pmrChan->txPttHid=o->lasttx = txtmp;
03206 if(o->debuglevel)printf("usbhid: tx set to %d\n",txtmp);
03207 buf[o->hid_gpio_loc] = 0;
03208 if (!o->invertptt)
03209 {
03210 if (txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
03211 }
03212 else
03213 {
03214 if (!txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
03215 }
03216 buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
03217 hid_set_outputs(o->usb_handle,buf);
03218 }
03219
03220 return(0);
03221 }
03222 #endif
03223
03224
03225 static void pmrdump(struct chan_usbradio_pvt *o)
03226 {
03227 t_pmr_chan *p;
03228 int i;
03229
03230 p=o->pmrChan;
03231
03232 printf("\nodump()\n");
03233
03234 pd(o->devicenum);
03235 ps(o->devstr);
03236
03237 pd(o->micmax);
03238 pd(o->spkrmax);
03239
03240 pd(o->rxdemod);
03241 pd(o->rxcdtype);
03242 pd(o->rxsdtype);
03243 pd(o->txtoctype);
03244
03245 pd(o->rxmixerset);
03246 pd(o->rxboostset);
03247
03248 pf(o->rxvoiceadj);
03249 pf(o->rxctcssadj);
03250 pd(o->rxsquelchadj);
03251
03252 ps(o->txctcssdefault);
03253 ps(o->txctcssfreq);
03254
03255 pd(o->numrxctcssfreqs);
03256 if(o->numrxctcssfreqs>0)
03257 {
03258 for(i=0;i<o->numrxctcssfreqs;i++)
03259 {
03260 printf(" %i = %s %s\n",i,o->rxctcss[i],o->txctcss[i]);
03261 }
03262 }
03263
03264 pd(o->b.rxpolarity);
03265 pd(o->b.txpolarity);
03266
03267 pd(o->txprelim);
03268 pd(o->txmixa);
03269 pd(o->txmixb);
03270
03271 pd(o->txmixaset);
03272 pd(o->txmixbset);
03273
03274 printf("\npmrdump()\n");
03275
03276 pd(p->devicenum);
03277
03278 printf("prxSquelchAdjust=%i\n",*(o->pmrChan->prxSquelchAdjust));
03279
03280 pd(p->rxCarrierPoint);
03281 pd(p->rxCarrierHyst);
03282
03283 pd(*p->prxVoiceAdjust);
03284 pd(*p->prxCtcssAdjust);
03285
03286 pd(p->rxfreq);
03287 pd(p->txfreq);
03288
03289 pd(p->rxCtcss->relax);
03290
03291 pd(p->numrxcodes);
03292 if(o->pmrChan->numrxcodes>0)
03293 {
03294 for(i=0;i<o->pmrChan->numrxcodes;i++)
03295 {
03296 printf(" %i = %s\n",i,o->pmrChan->pRxCode[i]);
03297 }
03298 }
03299
03300 pd(p->txTocType);
03301 ps(p->pTxCodeDefault);
03302 pd(p->txcodedefaultsmode);
03303 pd(p->numtxcodes);
03304 if(o->pmrChan->numtxcodes>0)
03305 {
03306 for(i=0;i<o->pmrChan->numtxcodes;i++)
03307 {
03308 printf(" %i = %s\n",i,o->pmrChan->pTxCode[i]);
03309 }
03310 }
03311
03312 pd(p->b.rxpolarity);
03313 pd(p->b.txpolarity);
03314 pd(p->b.dcsrxpolarity);
03315 pd(p->b.dcstxpolarity);
03316 pd(p->b.lsdrxpolarity);
03317 pd(p->b.lsdtxpolarity);
03318
03319 pd(p->txMixA);
03320 pd(p->txMixB);
03321
03322 pd(p->rxDeEmpEnable);
03323 pd(p->rxCenterSlicerEnable);
03324 pd(p->rxCtcssDecodeEnable);
03325 pd(p->rxDcsDecodeEnable);
03326 pd(p->b.ctcssRxEnable);
03327 pd(p->b.dcsRxEnable);
03328 pd(p->b.lmrRxEnable);
03329 pd(p->b.dstRxEnable);
03330 pd(p->smode);
03331
03332 pd(p->txHpfEnable);
03333 pd(p->txLimiterEnable);
03334 pd(p->txPreEmpEnable);
03335 pd(p->txLpfEnable);
03336
03337 if(p->spsTxOutA)pd(p->spsTxOutA->outputGain);
03338 if(p->spsTxOutB)pd(p->spsTxOutB->outputGain);
03339 pd(p->txPttIn);
03340 pd(p->txPttOut);
03341
03342 pd(p->tracetype);
03343
03344 return;
03345 }
03346
03347
03348
03349
03350 static int xpmr_config(struct chan_usbradio_pvt *o)
03351 {
03352
03353
03354 TRACEO(1,("xpmr_config()\n"));
03355
03356 if(o->pmrChan==NULL)
03357 {
03358 ast_log(LOG_ERROR,"pmr channel structure NULL\n");
03359 return 1;
03360 }
03361
03362 o->pmrChan->rxCtcss->relax = o->rxctcssrelax;
03363 o->pmrChan->txpower=0;
03364
03365 if(o->b.remoted)
03366 {
03367 o->pmrChan->pTxCodeDefault = o->set_txctcssdefault;
03368 o->pmrChan->pRxCodeSrc=o->set_rxctcssfreqs;
03369 o->pmrChan->pTxCodeSrc=o->set_txctcssfreqs;
03370
03371 o->pmrChan->rxfreq=o->set_rxfreq;
03372 o->pmrChan->txfreq=o->set_txfreq;
03373
03374
03375 }
03376 else
03377 {
03378
03379
03380 o->pmrChan->pTxCodeDefault = o->txctcssdefault;
03381 o->pmrChan->pRxCodeSrc = o->rxctcssfreqs;
03382 o->pmrChan->pTxCodeSrc = o->txctcssfreqs;
03383
03384 o->pmrChan->rxfreq = o->rxfreq;
03385 o->pmrChan->txfreq = o->txfreq;
03386 }
03387
03388 code_string_parse(o->pmrChan);
03389 if(o->pmrChan->rxfreq) o->pmrChan->b.reprog=1;
03390
03391 return 0;
03392 }
03393
03394
03395
03396 static struct chan_usbradio_pvt *store_config(struct ast_config *cfg, char *ctg)
03397 {
03398 struct ast_variable *v;
03399 struct chan_usbradio_pvt *o;
03400 struct ast_config *cfg1;
03401 int i;
03402 char fname[200];
03403 #ifdef NEW_ASTERISK
03404 struct ast_flags zeroflag = {0};
03405 #endif
03406 if (ctg == NULL) {
03407 traceusb1((" store_config() ctg == NULL\n"));
03408 o = &usbradio_default;
03409 ctg = "general";
03410 } else {
03411
03412 if (strcmp(ctg, "general") == 0) {
03413 o = &usbradio_default;
03414 } else {
03415
03416 if (!(o = ast_calloc(1, sizeof(*o))))
03417 return NULL;
03418 *o = usbradio_default;
03419 o->name = ast_strdup(ctg);
03420 if (!usbradio_active)
03421 usbradio_active = o->name;
03422 }
03423 }
03424 ast_mutex_init(&o->eepromlock);
03425 strcpy(o->mohinterpret, "default");
03426
03427 for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
03428 M_START((char *)v->name, (char *)v->value);
03429
03430
03431 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
03432 continue;
03433
03434 #if 0
03435 M_BOOL("autoanswer", o->autoanswer)
03436 M_BOOL("autohangup", o->autohangup)
03437 M_BOOL("overridecontext", o->overridecontext)
03438 M_STR("context", o->ctx)
03439 M_STR("language", o->language)
03440 M_STR("mohinterpret", o->mohinterpret)
03441 M_STR("extension", o->ext)
03442 M_F("callerid", store_callerid(o, v->value))
03443 #endif
03444 M_UINT("frags", o->frags)
03445 M_UINT("queuesize",o->queuesize)
03446 #if 0
03447 M_UINT("devicenum",o->devicenum)
03448 #endif
03449 M_UINT("debug", usbradio_debug)
03450 M_BOOL("rxcpusaver",o->rxcpusaver)
03451 M_BOOL("txcpusaver",o->txcpusaver)
03452 M_BOOL("invertptt",o->invertptt)
03453 M_F("rxdemod",store_rxdemod(o,(char *)v->value))
03454 M_BOOL("txprelim",o->txprelim);
03455 M_F("txmixa",store_txmixa(o,(char *)v->value))
03456 M_F("txmixb",store_txmixb(o,(char *)v->value))
03457 M_F("carrierfrom",store_rxcdtype(o,(char *)v->value))
03458 M_F("rxsdtype",store_rxsdtype(o,(char *)v->value))
03459 M_UINT("rxsqvox",o->rxsqvoxadj)
03460 M_STR("txctcssdefault",o->txctcssdefault)
03461 M_STR("rxctcssfreqs",o->rxctcssfreqs)
03462 M_STR("txctcssfreqs",o->txctcssfreqs)
03463 M_UINT("rxfreq",o->rxfreq)
03464 M_UINT("txfreq",o->txfreq)
03465 M_F("rxgain",store_rxgain(o,(char *)v->value))
03466 M_BOOL("rxboost",o->rxboostset)
03467 M_UINT("rxctcssrelax",o->rxctcssrelax)
03468 M_F("txtoctype",store_txtoctype(o,(char *)v->value))
03469 M_UINT("hdwtype",o->hdwtype)
03470 M_UINT("eeprom",o->wanteeprom)
03471 M_UINT("duplex",o->radioduplex)
03472 M_UINT("txsettletime",o->txsettletime)
03473 M_BOOL("rxpolarity",o->b.rxpolarity)
03474 M_BOOL("txpolarity",o->b.txpolarity)
03475 M_BOOL("dcsrxpolarity",o->b.dcsrxpolarity)
03476 M_BOOL("dcstxpolarity",o->b.dcstxpolarity)
03477 M_BOOL("lsdrxpolarity",o->b.lsdrxpolarity)
03478 M_BOOL("lsdtxpolarity",o->b.lsdtxpolarity)
03479 M_BOOL("loopback",o->b.loopback)
03480 M_BOOL("radioactive",o->b.radioactive)
03481 M_UINT("rptnum",o->rptnum)
03482 M_UINT("idleinterval",o->idleinterval)
03483 M_UINT("turnoffs",o->turnoffs)
03484 M_UINT("tracetype",o->tracetype)
03485 M_UINT("tracelevel",o->tracelevel)
03486 M_UINT("area",o->area)
03487 M_STR("ukey",o->ukey)
03488 M_END(;
03489 );
03490 }
03491
03492 o->debuglevel=0;
03493
03494 if (o == &usbradio_default)
03495 return NULL;
03496
03497 snprintf(fname,sizeof(fname) - 1,config1,o->name);
03498 #ifdef NEW_ASTERISK
03499 cfg1 = ast_config_load(fname,zeroflag);
03500 #else
03501 cfg1 = ast_config_load(fname);
03502 #endif
03503 o->rxmixerset = 500;
03504 o->txmixaset = 500;
03505 o->txmixbset = 500;
03506 o->rxvoiceadj = 0.5;
03507 o->rxctcssadj = 0.5;
03508 o->txctcssadj = 200;
03509 o->rxsquelchadj = 500;
03510 o->devstr[0] = 0;
03511 if (cfg1 && cfg1 != CONFIG_STATUS_FILEINVALID) {
03512 for (v = ast_variable_browse(cfg1, o->name); v; v = v->next) {
03513
03514 M_START((char *)v->name, (char *)v->value);
03515 M_UINT("rxmixerset", o->rxmixerset)
03516 M_UINT("txmixaset", o->txmixaset)
03517 M_UINT("txmixbset", o->txmixbset)
03518 M_F("rxvoiceadj",store_rxvoiceadj(o,(char *)v->value))
03519 M_F("rxctcssadj",store_rxctcssadj(o,(char *)v->value))
03520 M_UINT("txctcssadj",o->txctcssadj);
03521 M_UINT("rxsquelchadj", o->rxsquelchadj)
03522 M_STR("devstr", o->devstr)
03523 M_END(;
03524 );
03525 }
03526 ast_config_destroy(cfg1);
03527 } else ast_log(LOG_WARNING,"File %s not found, using default parameters.\n",fname);
03528
03529 if(o->wanteeprom)
03530 {
03531 ast_mutex_lock(&o->eepromlock);
03532 while(o->eepromctl)
03533 {
03534 ast_mutex_unlock(&o->eepromlock);
03535 usleep(10000);
03536 ast_mutex_lock(&o->eepromlock);
03537 }
03538 o->eepromctl = 1;
03539 ast_mutex_unlock(&o->eepromlock);
03540 }
03541
03542 if ((!usb_list_check(o->devstr)) || find_desc_usb(o->devstr))
03543 {
03544 char *s;
03545
03546 for(s = usb_device_list; *s; s += strlen(s) + 1)
03547 {
03548 if (!find_desc_usb(s)) break;
03549 }
03550 if (!*s)
03551 {
03552 ast_log(LOG_WARNING,"Unable to assign USB device for channel %s\n",o->name);
03553 goto error;
03554 }
03555 ast_log(LOG_NOTICE,"Assigned USB device %s to usbradio channel %s\n",s,o->name);
03556 strcpy(o->devstr,s);
03557 }
03558
03559 i = usb_get_usbdev(o->devstr);
03560 if (i < 0)
03561 {
03562 ast_log(LOG_ERROR,"Not able to find alsa USB device\n");
03563 goto error;
03564 }
03565 o->devicenum = i;
03566
03567 o->micmax = amixer_max(o->devicenum,MIXER_PARAM_MIC_CAPTURE_VOL);
03568 o->spkrmax = amixer_max(o->devicenum,MIXER_PARAM_SPKR_PLAYBACK_VOL);
03569 o->lastopen = ast_tvnow();
03570 o->dsp = ast_dsp_new();
03571 if (o->dsp)
03572 {
03573 #ifdef NEW_ASTERISK
03574 ast_dsp_set_features(o->dsp,DSP_FEATURE_DIGIT_DETECT);
03575 ast_dsp_set_digitmode(o->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF);
03576 #else
03577 ast_dsp_set_features(o->dsp,DSP_FEATURE_DTMF_DETECT);
03578 ast_dsp_digitmode(o->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF);
03579 #endif
03580 }
03581
03582 if(o->pmrChan==NULL)
03583 {
03584 t_pmr_chan tChan;
03585
03586
03587 memset(&tChan,0,sizeof(t_pmr_chan));
03588
03589 tChan.pTxCodeDefault = o->txctcssdefault;
03590 tChan.pRxCodeSrc = o->rxctcssfreqs;
03591 tChan.pTxCodeSrc = o->txctcssfreqs;
03592
03593 tChan.rxDemod=o->rxdemod;
03594 tChan.rxCdType=o->rxcdtype;
03595 tChan.rxSqVoxAdj=o->rxsqvoxadj;
03596
03597 if (o->txprelim)
03598 tChan.txMod = 2;
03599
03600 tChan.txMixA = o->txmixa;
03601 tChan.txMixB = o->txmixb;
03602
03603 tChan.rxCpuSaver=o->rxcpusaver;
03604 tChan.txCpuSaver=o->txcpusaver;
03605
03606 tChan.b.rxpolarity=o->b.rxpolarity;
03607 tChan.b.txpolarity=o->b.txpolarity;
03608
03609 tChan.b.dcsrxpolarity=o->b.dcsrxpolarity;
03610 tChan.b.dcstxpolarity=o->b.dcstxpolarity;
03611
03612 tChan.b.lsdrxpolarity=o->b.lsdrxpolarity;
03613 tChan.b.lsdtxpolarity=o->b.lsdtxpolarity;
03614
03615 tChan.tracetype=o->tracetype;
03616 tChan.tracelevel=o->tracelevel;
03617 tChan.rptnum=o->rptnum;
03618 tChan.idleinterval=o->idleinterval;
03619 tChan.turnoffs=o->turnoffs;
03620 tChan.area=o->area;
03621 tChan.ukey=o->ukey;
03622 tChan.name=o->name;
03623
03624 o->pmrChan=createPmrChannel(&tChan,FRAME_SIZE);
03625
03626 o->pmrChan->radioDuplex=o->radioduplex;
03627 o->pmrChan->b.loopback=0;
03628 o->pmrChan->txsettletime=o->txsettletime;
03629 o->pmrChan->rxCpuSaver=o->rxcpusaver;
03630 o->pmrChan->txCpuSaver=o->txcpusaver;
03631
03632 *(o->pmrChan->prxSquelchAdjust) =
03633 ((999 - o->rxsquelchadj) * 32767) / 1000;
03634
03635 *(o->pmrChan->prxVoiceAdjust)=o->rxvoiceadj*M_Q8;
03636 *(o->pmrChan->prxCtcssAdjust)=o->rxctcssadj*M_Q8;
03637 o->pmrChan->rxCtcss->relax=o->rxctcssrelax;
03638 o->pmrChan->txTocType = o->txtoctype;
03639
03640 if ( (o->txmixa == TX_OUT_LSD) ||
03641 (o->txmixa == TX_OUT_COMPOSITE) ||
03642 (o->txmixb == TX_OUT_LSD) ||
03643 (o->txmixb == TX_OUT_COMPOSITE))
03644 {
03645 set_txctcss_level(o);
03646 }
03647
03648 if( (o->txmixa!=TX_OUT_VOICE) && (o->txmixb!=TX_OUT_VOICE) &&
03649 (o->txmixa!=TX_OUT_COMPOSITE) && (o->txmixb!=TX_OUT_COMPOSITE)
03650 )
03651 {
03652 ast_log(LOG_ERROR,"No txvoice output configured.\n");
03653 }
03654
03655 if( o->txctcssfreq[0] &&
03656 o->txmixa!=TX_OUT_LSD && o->txmixa!=TX_OUT_COMPOSITE &&
03657 o->txmixb!=TX_OUT_LSD && o->txmixb!=TX_OUT_COMPOSITE
03658 )
03659 {
03660 ast_log(LOG_ERROR,"No txtone output configured.\n");
03661 }
03662
03663 if(o->b.radioactive)
03664 {
03665
03666
03667
03668
03669
03670 usbradio_active = o->name;
03671
03672
03673
03674 ast_log(LOG_NOTICE,"radio active set to [%s]\n",o->name);
03675 }
03676 }
03677
03678 xpmr_config(o);
03679
03680 TRACEO(1,("store_config() 120\n"));
03681 mixer_write(o);
03682 TRACEO(1,("store_config() 130\n"));
03683 mult_set(o);
03684 TRACEO(1,("store_config() 140\n"));
03685 hidhdwconfig(o);
03686
03687 TRACEO(1,("store_config() 200\n"));
03688
03689 #ifndef NEW_ASTERISK
03690 if (pipe(o->sndcmd) != 0) {
03691 ast_log(LOG_ERROR, "Unable to create pipe\n");
03692 goto error;
03693 }
03694
03695 ast_pthread_create_background(&o->sthread, NULL, sound_thread, o);
03696 #endif
03697
03698
03699 if (o != &usbradio_default) {
03700 o->next = usbradio_default.next;
03701 usbradio_default.next = o;
03702 }
03703 TRACEO(1,("store_config() complete\n"));
03704 return o;
03705
03706 error:
03707 if (o != &usbradio_default)
03708 free(o);
03709 return NULL;
03710 }
03711
03712
03713 #if DEBUG_FILETEST == 1
03714
03715
03716
03717 int RxTestIt(struct chan_usbradio_pvt *o)
03718 {
03719 const int numSamples = SAMPLES_PER_BLOCK;
03720 const int numChannels = 16;
03721
03722 i16 sample,i,ii;
03723
03724 i32 txHangTime;
03725
03726 i16 txEnable;
03727
03728 t_pmr_chan tChan;
03729 t_pmr_chan *pChan;
03730
03731 FILE *hInput=NULL, *hOutput=NULL, *hOutputTx=NULL;
03732
03733 i16 iBuff[numSamples*2*6], oBuff[numSamples];
03734
03735 printf("RxTestIt()\n");
03736
03737 pChan=o->pmrChan;
03738 pChan->b.txCapture=1;
03739 pChan->b.rxCapture=1;
03740
03741 txEnable = 0;
03742
03743 hInput = fopen("/usr/src/xpmr/testdata/rx_in.pcm","r");
03744 if(!hInput){
03745 printf(" RxTestIt() File Not Found.\n");
03746 return 0;
03747 }
03748 hOutput = fopen("/usr/src/xpmr/testdata/rx_debug.pcm","w");
03749
03750 printf(" RxTestIt() Working...\n");
03751
03752 while(!feof(hInput))
03753 {
03754 fread((void *)iBuff,2,numSamples*2*6,hInput);
03755
03756 if(txHangTime)txHangTime-=numSamples;
03757 if(txHangTime<0)txHangTime=0;
03758
03759 if(pChan->rxCtcss->decode)txHangTime=(8000/1000*2000);
03760
03761 if(pChan->rxCtcss->decode && !txEnable)
03762 {
03763 txEnable=1;
03764
03765 }
03766 else if(!pChan->rxCtcss->decode && txEnable)
03767 {
03768 txEnable=0;
03769 }
03770
03771 PmrRx(pChan,iBuff,oBuff);
03772
03773 if (fwrite((void *)pChan->prxDebug,2,numSamples*numChannels,hOutput) != numSamples * numChannels) {
03774 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
03775 }
03776 }
03777 pChan->b.txCapture=0;
03778 pChan->b.rxCapture=0;
03779
03780 if(hInput)fclose(hInput);
03781 if(hOutput)fclose(hOutput);
03782
03783 printf(" RxTestIt() Complete.\n");
03784
03785 return 0;
03786 }
03787 #endif
03788
03789 #ifdef NEW_ASTERISK
03790
03791 static char *res2cli(int r)
03792
03793 {
03794 switch (r)
03795 {
03796 case RESULT_SUCCESS:
03797 return(CLI_SUCCESS);
03798 case RESULT_SHOWUSAGE:
03799 return(CLI_SHOWUSAGE);
03800 default:
03801 return(CLI_FAILURE);
03802 }
03803 }
03804
03805 static char *handle_console_key(struct ast_cli_entry *e,
03806 int cmd, struct ast_cli_args *a)
03807 {
03808 char *argv[] = { "radio", "key", NULL };
03809
03810 switch (cmd) {
03811 case CLI_INIT:
03812 e->command = "radio key";
03813 e->usage = key_usage;
03814 return NULL;
03815 case CLI_GENERATE:
03816 return NULL;
03817 }
03818 return res2cli(console_key(a->fd, 2, argv));
03819 }
03820
03821 static char *handle_console_unkey(struct ast_cli_entry *e,
03822 int cmd, struct ast_cli_args *a)
03823 {
03824 char *argv[] = { "radio", "unkey", NULL };
03825 switch (cmd) {
03826 case CLI_INIT:
03827 e->command = "radio unkey";
03828 e->usage = unkey_usage;
03829 return NULL;
03830 case CLI_GENERATE:
03831 return NULL;
03832 }
03833 return res2cli(console_unkey(a->fd, 2, argv));
03834 }
03835
03836 static char *handle_radio_tune(struct ast_cli_entry *e,
03837 int cmd, struct ast_cli_args *a)
03838 {
03839 char *argv[5] = { "radio", "tune", a->argc > 2 ? (char *) a->argv[2] : NULL, a->argc > 3 ? (char *) a->argv[3] : NULL };
03840 switch (cmd) {
03841 case CLI_INIT:
03842 e->command = "radio tune";
03843 e->usage = radio_tune_usage;
03844 return NULL;
03845 case CLI_GENERATE:
03846 return NULL;
03847 }
03848 return res2cli(radio_tune(a->fd, a->argc, argv));
03849 }
03850
03851 static char *handle_radio_debug(struct ast_cli_entry *e,
03852 int cmd, struct ast_cli_args *a)
03853 {
03854 switch (cmd) {
03855 case CLI_INIT:
03856 e->command = "radio debug";
03857 e->usage = radio_tune_usage;
03858 return NULL;
03859 case CLI_GENERATE:
03860 return NULL;
03861 }
03862 return res2cli(radio_set_debug(a->fd, a->argc, NULL ));
03863 }
03864
03865 static char *handle_radio_debug_off(struct ast_cli_entry *e,
03866 int cmd, struct ast_cli_args *a)
03867 {
03868 switch (cmd) {
03869 case CLI_INIT:
03870 e->command = "radio debug off";
03871 e->usage = radio_tune_usage;
03872 return NULL;
03873 case CLI_GENERATE:
03874 return NULL;
03875 }
03876 return res2cli(radio_set_debug_off(a->fd, a->argc, NULL ));
03877 }
03878
03879 static char *handle_radio_active(struct ast_cli_entry *e,
03880 int cmd, struct ast_cli_args *a)
03881 {
03882 char *argv[4] = { "radio", "active", a->argc > 2 ? (char *) a->argv[2] : NULL, };
03883 switch (cmd) {
03884 case CLI_INIT:
03885 e->command = "radio active";
03886 e->usage = active_usage;
03887 return NULL;
03888 case CLI_GENERATE:
03889 return NULL;
03890 }
03891 return res2cli(radio_active(a->fd, a->argc, argv));
03892 }
03893
03894 static char *handle_set_xdebug(struct ast_cli_entry *e,
03895 int cmd, struct ast_cli_args *a)
03896 {
03897 char *argv[5] = { "radio", "set", "xdebug", a->argc == 4 ? (char *) a->argv[3] : NULL, };
03898 switch (cmd) {
03899 case CLI_INIT:
03900 e->command = "radio set xdebug";
03901 e->usage = active_usage;
03902 return NULL;
03903 case CLI_GENERATE:
03904 return NULL;
03905 }
03906 return res2cli(radio_set_xpmr_debug(a->fd, a->argc, argv));
03907 }
03908
03909
03910 static struct ast_cli_entry cli_usbradio[] = {
03911 AST_CLI_DEFINE(handle_console_key,"Simulate Rx Signal Present"),
03912 AST_CLI_DEFINE(handle_console_unkey,"Simulate Rx Signal Loss"),
03913 AST_CLI_DEFINE(handle_radio_tune,"Radio Tune"),
03914 AST_CLI_DEFINE(handle_radio_debug,"Radio Debug On"),
03915 AST_CLI_DEFINE(handle_radio_debug_off,"Radio Debug Off"),
03916 AST_CLI_DEFINE(handle_radio_active,"Change commanded device"),
03917 AST_CLI_DEFINE(handle_set_xdebug,"Radio set xpmr debug level")
03918 };
03919
03920 #endif
03921
03922 #include "./xpmr/xpmr.c"
03923 #ifdef HAVE_XPMRX
03924 #include "./xpmrx/xpmrx.c"
03925 #endif
03926
03927
03928
03929 static int load_module(void)
03930 {
03931 struct ast_config *cfg = NULL;
03932 char *ctg = NULL;
03933 #ifdef NEW_ASTERISK
03934 struct ast_flags zeroflag = {0};
03935 #endif
03936
03937 if (hid_device_mklist()) {
03938 ast_log(LOG_NOTICE, "Unable to make hid list\n");
03939 return AST_MODULE_LOAD_DECLINE;
03940 }
03941
03942 usb_list_check("");
03943
03944 usbradio_active = NULL;
03945
03946
03947 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
03948
03949
03950 #ifdef NEW_ASTERISK
03951 if (!(cfg = ast_config_load(config,zeroflag)) || cfg == CONFIG_STATUS_FILEINVALID) {
03952 #else
03953 if (!(cfg = ast_config_load(config))) || cfg == CONFIG_STATUS_FILEINVALID {
03954 #endif
03955 ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
03956 return AST_MODULE_LOAD_DECLINE;
03957 }
03958
03959 do {
03960 store_config(cfg, ctg);
03961 } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
03962
03963 ast_config_destroy(cfg);
03964
03965 if (find_desc(usbradio_active) == NULL) {
03966 ast_log(LOG_NOTICE, "radio active device %s not found\n", usbradio_active);
03967
03968
03969 return AST_MODULE_LOAD_DECLINE;
03970 }
03971
03972 if (ast_channel_register(&usbradio_tech)) {
03973 ast_log(LOG_ERROR, "Unable to register channel type 'usb'\n");
03974 return AST_MODULE_LOAD_DECLINE;
03975 }
03976
03977 ast_cli_register_multiple(cli_usbradio, ARRAY_LEN(cli_usbradio));
03978
03979 return AST_MODULE_LOAD_SUCCESS;
03980 }
03981
03982
03983 static int unload_module(void)
03984 {
03985 struct chan_usbradio_pvt *o;
03986
03987 ast_log(LOG_WARNING, "unload_module() called\n");
03988
03989 ast_channel_unregister(&usbradio_tech);
03990 ast_cli_unregister_multiple(cli_usbradio, ARRAY_LEN(cli_usbradio));
03991
03992 for (o = usbradio_default.next; o; o = o->next) {
03993
03994 ast_log(LOG_WARNING, "destroyPmrChannel() called\n");
03995 if(o->pmrChan)destroyPmrChannel(o->pmrChan);
03996
03997 #if DEBUG_CAPTURES == 1
03998 if (frxcapraw) { fclose(frxcapraw); frxcapraw = NULL; }
03999 if (frxcaptrace) { fclose(frxcaptrace); frxcaptrace = NULL; }
04000 if (frxoutraw) { fclose(frxoutraw); frxoutraw = NULL; }
04001 if (ftxcapraw) { fclose(ftxcapraw); ftxcapraw = NULL; }
04002 if (ftxcaptrace) { fclose(ftxcaptrace); ftxcaptrace = NULL; }
04003 if (ftxoutraw) { fclose(ftxoutraw); ftxoutraw = NULL; }
04004 #endif
04005
04006 close(o->sounddev);
04007 #ifndef NEW_ASTERISK
04008 if (o->sndcmd[0] > 0) {
04009 close(o->sndcmd[0]);
04010 close(o->sndcmd[1]);
04011 }
04012 #endif
04013 if (o->dsp) ast_dsp_free(o->dsp);
04014 if (o->owner)
04015 ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
04016 if (o->owner)
04017 return -1;
04018
04019
04020 }
04021 return 0;
04022 }
04023
04024 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "usb Console Channel Driver");
04025
04026
04027
04028